编程

0x00 Create a new post/page

1
2
~# hexo new "Post Title"
~# hexo new page "Download"

0x01 Put codes blocks on your post

Use keyword tag codeblock and endcodeblock

1
2
3
{% codeblock lang:javascript %}
alert('Hello World!');
{% endcodeblock %}

Or just use three backquotes

1
2
3
4
\`\`\`[language] [title] [url] [link text]
code snippet
\`\`\`
#remove the \ before `

Images

1
{% img [class names] /path/to/image [width] [height] [title text [alt text]] %}

Links

1
{% link text url [external] [title] %}

0x03 Organize your posts resources

In _config.yml, set post_asset_folder as true

1
post_asset_folder: true

Then your _posts directory maybe such as this

1
2
3
4
5
6
7
8
9
root@debian:~/chorder.net/source# tree _posts/
_posts/
├── hello-world
│   └── 20180510.jpg
├── hello-world.md
├── hexo-start-up
└── hexo-start-up.md

2 directories, 3 files

You can directly include images from resources directory:

1
{% asset_img xxx.jpg ALT TITLE %}

0x04 Organize your post categories / tags

Your may want to organize your posts as different categories and tags.
First you need to define categories and tags directories in _config.yml, default is like this

1
2
3
4
5
6
# Directory
source_dir: source
public_dir: public
tag_dir: tags
archive_dir: archives
category_dir: categories

Then you can generate a new page to navigate the posts

1
2
~# hexo new page "categories"
~# hexo new page "tags"

After that, the tags and categories directory will being created in source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@debian:~/chorder.net/source# tree
.
├── categories
│   └── index.md
├── _posts
│   ├── hello-world
│   │   └── 20180510.jpg
│   ├── hello-world.md
│   ├── hexo-start-up
│   └── hexo-start-up.md
└── tags
└── index.md

5 directories, 5 files

And on the next time when you creating a new post, you could statement the category and tags of your post,
on the head of post markdown file, just like:

1
2
3
4
5
6
---
title: 10 basic operations of Hexo
date: 2018-05-17 17:05:24
categories: default
tags: default
---

The archives of tags and categories will showing in the site automatically.

0x05 Publish pages on a simple local server

In your hexo directory, run

1
~# npm install hexo-server --save

Then start the server:

1
~# hexo server -p PORT

Or if your want publish static pages as an production envirement, you should first generate static files:

1
~# hexo generate

And then start the server as static mode, it will only deploy pages which included in public directory:

1
~# hexo server -s

0x06 Directly include code from resource

1
{% include_code [title] [lang:language] path/to/file %}

0x07 Insert a video from youtube / vimeo

1
{% youtube video_id %}
1
{% vimeo video_id %}

0x08 Quote an article / resource

1
2
3
4
5
6
7
8
9
# article
{% post_path slug %}
{% post_link slug [title] %}

# resource
{% asset_path slug %}
{% asset_img slug [title] %}
{% asset_link slug [title] %}

0x09 Sitemap & robots.txt

As for optimize your site with a better SEO, ensure you has create sitemap:

1
2
3
4
#for google sitemap, install this package
npm install hexo-generator-sitemap --save
#for baidu(China) sitemap, instal this package
npm install hexo-generator-baidu-sitemap --save

Over that, tell the spider what you have done, write this in your robots.txt, and save it at source directory:

1
2
Sitemap: http://YOUR DOMAIN/sitemap.xml
Sitemap: http://YOUR DOMAIN/baidusitemap.xml

Example robots.txt as mine:

1
2
3
4
5
6
7
User-agent: *
Allow: /
Allow: /archives/
Allow: /categories/
Allow: /tags/
Sitemap: https://chorder.net/sitemap.xml
Sitemap: https://chorder.net/baidusitemap.xml

You can see both above at:

Sitemap Baidu Sitemap robots.txt

不知原文出自哪里,如果您是作者,请私信我补充来源链接。

前言

记录一些排查常见日志的命令,方法wiki,欢迎补充(Markdown 语法)。

常用命令

  1. 查找关键词并统计行数
    1
    cat 2015_7_25_test_access.log | grep "sqlmap" | wc -l
  2. 删除含有匹配字符的行
    1
    sed -i '/Indy Library/d' 2015_7_25_test_access.log
  3. 查找所有日志中的关键词
    1
    find ./ -name "*.log" |xargs grep "sqlmap" |wc -l
  4. 获取特殊行(如id)并且排序统计
    1
    cat cszl988.log | awk '{print $1}' | awk -F : '{print $2}' | sort -u | wc -l
  5. 正则匹配内容(如提取ip)
    1
    grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}"
  6. 去重并统计数量
    1
    tail 3.log | awk '{print $7}' | sort | uniq -c
  7. 批量提取(全流量中)数据包并且过滤数据
    1
    2
    3
    4
    5
    #!/bin/bash
    for file in ` ls $1 `
    do
    parse_pcap -vvb $file | grep -v "Host:" | grep -v "Cookie:" | grep -v "User-Agent:" | grep -v "Accept:" | grep -v "Accept:" | grep -v "Accept-Language:" | grep -v "Accept-Encoding:" | grep -v "Connection:" | grep -v "Content-Type:" | grep -v "Content-Length" | grep -v "Server"
    done
  8. url 解码
    1
    cat luban.log | grep sqlmap | awk '{print $7}' | xargs python -c 'import sys, urllib; print urllib.unquote(sys.argv[1])'
  9. 欢迎补充….

示范:xxxx站注入日志排查

  • 查看所有sqlmap注入记录条数
    1
    2
    [root@pentest temp]# cat luban.log | grep sqlmap | wc -l
    1241
  • 预览几条url
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    cat luban.log | grep sqlmap | awk '{print $7}' | more
    /news.php?id=771%28.%28%22%29.%27%29%29%27&fid=168
    /news.php?id=771%27IddP%3C%27%22%3EvCBw&fid=168
    /news.php?id=771%29%20AND%201148%3D8887%20AND%20%288975%3D8975&fid=168
    /news.php?id=771%29%20AND%208790%3D8790%20AND%20%287928%3D7928&fid=168
    /news.php?id=771%20AND%204294%3D9647&fid=168
    /news.php?id=771%20AND%208790%3D8790&fid=168
    /news.php?id=771%27%29%20AND%205983%3D7073%20AND%20%28%27UwRr%27%3D%27UwRr&fid=168
    /news.php?id=771%27%29%20AND%208790%3D8790%20AND%20%28%27hwaT%27%3D%27hwaT&fid=168
    /news.php?id=771%27%20AND%206578%3D7565%20AND%20%27EoTZ%27%3D%27EoTZ&fid=168
    /news.php?id=771%27%20AND%208790%3D8790%20AND%20%27lBdL%27%3D%27lBdL&fid=168
    /news.php?id=771%25%27%20AND%205177%3D1107%20AND%20%27%25%27%3D%27&fid=168
    /news.php?id=771%25%27%20AND%208790%3D8790%20AND%20%27%25%27%3D%27&fid=168
  • 方便查看 urldecode
    1
    2
    3
    4
    5
    6
    7
    cat luban.log | grep sqlmap | awk '{print $7}' | xargs python -c 'import sys, urllib; print urllib.unquote(sys.argv[1])'
    /news.php?id=771&fid=168
    /news.php?id=771&fid=168 AND ASCII(SUBSTRING((SELECT DISTINCT(COALESCE(CAST(schemaname AS CHARACTER(10000)),(CHR(32)))) FROM pg_tables OFFSET 1 LIMIT 1)::text FROM 3 FOR 1))>
    97
    /news.php?id=771&fid=168 UNION ALL SELECT NULL,(CHR(113)||CHR(122)||CHR(106)||CHR(120)||CHR(113))||(CHR(103)||CHR(75)||CHR(78)||CHR(87)||CHR(76)||CHR(74)||CHR(110)||CHR(1
    15)||CHR(100)||CHR(85))||(CHR(113)||CHR(122)||CHR(120)||CHR(113)||CHR(113)),NULL,NULL,NULL,NULL,NULL,NULL,NULL UNION ALL SELECT NULL,(CHR(113)||CHR(122)||CHR(106)||CHR(120)||CHR(113))||(CHR(113)||CHR(71)||C
    HR(74)||CHR(82)||CHR(101)||CHR(120)||CHR(69)||CHR(112)||CHR(117)||CHR(79))||(CHR(113)||CHR(122)||CHR(120)||CHR(113)||CHR(113)),NULL,NULL,NULL,NULL,NULL,NULL,NULL--

首先,如果没有签名密钥,先生成密钥:

1
keytool -genkey -alias android.keystore -keyalg RSA -validity 20000 -keystore android.keystore

接着会提示你输入密码、地区、国家等等,根据提示输入即可。
我这里的用户名和密码都是android

然后使用密钥进行签名

1
jarsigner -keystore android.keystore -storepass android -keypass android XXX.apk android.keystore

keytool和jarsigner都是jdk自带的工具,配好环境变量就可以直接在命令行使用的。

创建本地分支

1
git branch NAME

切换本地分支

1
git checkout NAME

查看远程分支

1
git branch -r

推送本地分支到远程仓库

1
git push origin NAME

引用子模块

1
2
3
git submodule add RESPOSITORIES PATH
# RESPOSSITORIES 是仓库地址
# PATH是本地路径,默认是当前目录

克隆带有子模块的项目

1
2
3
4
git clone XXX
cd XXX
git submodule init
git submodule update

跟踪其他分支

1
2
3
4
5
git remote add upstream XXX.git
git fetch upstream
git checkout master
git rebase upstream/master
git push -f origin master

https://startssl.com 这个网站可以给我们免费提供可信任的https证书,这里简单介绍一下配置的过程。
首先服务器需要安装openssl和apache的mod_ssl.so模块,并且需要在httpd.conf中开启这个模块。
完成上述操作之后就可以使用openssl生成你自己的证书了。
这里有些知识你需要了解一下。
https的整个服务中,你需要了解这些文件的作用:

server.key 服务器的私钥
server.crt 服务器的证书文件
server.csr 服务器证书请求文件
root.crt   根证书

这些文件是这样生成的

首先运行

1
openssl req -new -nodes -keyout chorder.net.key -out chorder.net.csr

生成服务器证书和服务器证书请求文件,过程中会要求输入很多有关证书的信息和密码。
这一步完成之后会生成两个文件,chorder.net.key和chorder.net.csr
这时候去startssl网站上注册帐号,然后提交自己生成的.csr文件,让startssl为你生成一个
服务器证书和根证书。
把两个.crt结尾的证书拷贝到服务器的/etc/pki/tls/certs/下,把.key和.csr文件拷贝到/etc/pki/tls/private/下。(只针对CentOS服务器,其他服务器请自行百度)。
另外还需要将/etc/pki/tls/下的cert.pem(如果没有则创建一个)链接指向到/etc/pki/tls/certs/root.crt
这样用火狐浏览器访问的时候才不会报 SEC_ERROR_UNKNOWN_ISSUER 这个错误。
这个cert.pem就是证书链,只有当你的服务器证书包含在startssl网站的证书链中,客户端才会认为你的证书是可信的。

最后,修改两个文件。

1 /etc/httpd/conf.d/ssl.conf

在该文件中修改以下内容:

指定服务器证书

1
SSLCertificateFile /etc/pki/tls/certs/chorder.net.crt

指定服务器私钥

1
SSLCertificateKeyFile /etc/pki/tls/private/chorder.net.key

指定服务器证书链

1
SSLCertificateChainFile /etc/pki/tls/certs/root-bundle.crt

2 /etc/httpd/conf/httpd.conf

为你的主机(我这里是虚拟主机)创建配置

我的配置如下

NameVirtualHost *:443
<VirtualHost *:443>
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/chorder.net.crt
    SSLCertificateKeyFile /etc/pki/tls/private/chorder.net.key
    SSLCertificateChainFile /etc/pki/tls/cert.pem
    ServerName chorder.net
    ServerAdmin ×××××
    DocumentRoot ×××××
    ErrorLog ×××××
    CustomLog ×××××
</VirtualHost>

其实就是http配置文件下多加了几行。
配置好这些以后,重启服务,完成。
另外,如果你希望访问你的域名直接跳转到https端口,可以写一段js来跳转,如果觉得
写代码太麻烦,可以在根目录的.htaccess文件中加入这两行来帮你自动跳转:

1
2
RewriteCond %{SERVER_PORT} !^443$
RewriteRule (.*) https://%{SERVER_NAME}/$1 [R]

这样就将默认端口指定为443,并且将所有http的请求重写为https.

一直想给安装一个缩略图点击弹出的插件,但是找了找几乎都是用的php来做的,插件的使用和安装极其繁琐,于是上网查了些demo,自己实现了一个纯js的图片弹出插件。

实现的思路是通过编写hook图片的onclick事件的函数,在函数中对body追加div元素,再将传入的图片对象放入元素中,同时再监听div的onclilck事件,当捕捉到点击,再关闭(其实是隐藏)弹出的div。
通过在函数初始化的时候收集页面所有的img元素,再为每个img元素增加onclick=”picHook(this)”这条属性,这样当图片在被点击时,这个函数就能自动创建div蒙板背景,并获取被点击图片的宽度和高度,同时生成一个新的和图片一样大小的div来显示图片。当蒙板再次被点击时,hook事件再次响应,并将蒙板和图片div的style置为none,弹出的图片就被关闭了。
说起来很简单,做起来就更简单了,简单到只需要一个函数即可实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<script>
function picHook(pic){
/*图片对象*/
var imgs = document.getElementsByTagName("img");
/*前景div*/
var light = document.getElementById('light') || document.createElement("div");
/*背景div*/
var bg = document.getElementById('bg') || document.createElement("div");
/*图片放大*/
var s_pic = document.getElementById('s_pic') || document.createElement("img");
/*css对象*/
var css = document.createElement("style");
/*css样式*/
var csstext = '\
.pic_bg{\
position: absolute;\
margin:0 auto; \
top: 0%;\
left: 0%;\
right: 0%;\
width: 100%;\
padding-bottom: 1000%;\
background-color: black;\
z-index:1001;\
opacity:.80;\
filter: alpha(opacity=80);\
overflow:scroll;\
}\

.pic_div {\
margin-bottom: auto;\
position: fixed;\
left:30%;\
top:20%;\
width: 100%;\
padding-top:25px;\
margin-left:-250px;\
margin-top:-100px;\
z-index:1002;\
}';
/*收集页面所有图片对象*/
for(i=0; i<imgs.length;i++){
imgs[i].setAttribute("onclick", "picHook(this)" );
}
css.type = "text/css";

/*关闭图像*/
if( !pic ){
bg.style.display = light.style.display = "none";
}

/*ie兼容*/
if(css.styleSheet){
css.styleSheet.cssText = csstext;
}else{
css.appendChild(document.createTextNode(csstext));
}

s_pic.setAttribute("id", "s_pic");
s_pic.setAttribute("src", pic.src);
s_pic.setAttribute("width","70%");
s_pic.setAttribute("height","65%");
s_pic.setAttribute("margin","0 auto");
s_pic.style.display = 'block';
light.setAttribute("id", "light");
light.setAttribute("class", "pic_div");
light.style.display = 'block';
light.appendChild(s_pic);
light.setAttribute("onclick", "picHook()");
bg.setAttribute("id", "bg");
bg.setAttribute("class", "pic_bg");
bg.setAttribute("onclick", "picHook()");
bg.style.display = light.style.display;
document.getElementsByTagName("head")[0].appendChild(css);
document.body.appendChild(bg);
document.body.appendChild(light);
}
</script>

将这段代码保存在页面的head中,再将body的onload事件绑定到picHook()函数,你的页面中就也可以实现图片点击弹出大图啦。
还存在一点小bug,主要是因为我不太熟悉css,导致div的样式做的有点难看。
css的样式我是直接声明在js里的,这样就不用再另外创建css文件了。
强迫症,没办法。
等有时间再琢磨琢磨css,优化下样式。

快捷键 操作
Ctrl + a 移到命令行首
Ctrl + e 移到命令行尾
Ctrl + f 按字符前移(右向)
Ctrl + b 按字符后移(左向)
Alt + f 按单词前移(右向)
Alt + b 按单词后移(左向)
Ctrl + xx 在命令行首和光标之间移动
Ctrl + u 从光标处删除至命令行首
Ctrl + k 从光标处删除至命令行尾
Ctrl + w 从光标处删除至字首
Alt + d 从光标处删除至字尾
Ctrl + d 删除光标处的字符
Ctrl + h 删除光标前的字符
Ctrl + y 粘贴至光标后
Alt + c 从光标处更改为首字母大写的单词
Alt + u 从光标处更改为全部大写的单词
Alt + l 从光标处更改为全部小写的单词
Ctrl + t 交换光标处和之前的字符
Alt + t 交换光标处和之前的单词
Alt + Backspace 与 Ctrl + w 类似 重新执行命令
Ctrl + r 逆向搜索命令历史
Ctrl + g 从历史搜索模式退出
Ctrl + p 历史中的上一条命令
Ctrl + n 历史中的下一条命令
Alt + . 使用上一条命令的最后一个参数 控制命令
Ctrl + l 清屏
Ctrl + o 执行当前命令,并选择上一条命令
Ctrl + s 阻止屏幕输出
Ctrl + q 允许屏幕输出
Ctrl + c 终止命令
Ctrl + z 挂起命令 Bang (!)命令
!! 执行上一条命令
!blah 执行最近的以 blah 开头的命令,如 !ls
!blah:p 仅打印输出,而不执行
!$ 上一条命令的最后一个参数,与 Alt + . 相同
!$:p 打印输出 !$ 的内容
!* 上一条命令的所有参数
!*:p 打印输出 !* 的内容
^blah 删除上一条命令中的 blah
^blah^foo 将上一条命令中的 blah 替换为 foo
^blah^foo^ 将上一条命令中所有的 blah 都替换为 foo

定义类

定义类的过程就是定义类的属性的过程。类的属性就是类的静态属性的简称,指类内包含的各项数据。类的服务被称为成员函数或方法。

继承(extends)

通过定义继承方法,子类可以获得父类的所有属性和方法。

接口(implements)

说明当前类中实现了哪个接口定义的功能和方法,是Java语言中实现多重继承的一种机制

修饰符

  • 访问控制符
  • 抽象类说明符
  • 最终说明符

类的属性

描述了类内部的信息,又称为类的静态属性。类属性为简单变量。

【修饰符】 变量类型 变量名【=变量初值】
【修饰符】 类名 对象名 【=new 类名(实际参数列表)】

若使用另一个类的对象作为当前类所定义的类的属性,要保证该对象所在的类在当前类中是可已被当前类所引用的

类属性的修饰符

  • 访问控制符
  • 静态修饰符static
  • 最终修饰符final
  • 易失修饰符volatile
  • 过渡修饰符transient

类的方法(成员函数)

用来规定类属性上的操作,实现类内部功能的机制,也是类与外界交互的窗口。

声明方法的语法:
【修饰符】返回值类型 方法名(参数列表)
Trows 例外名1,例外名2,… {
方法体:
局部变量声明;
语句序列;
}

方法的修饰符

  • 访问控制符
  • 静态修饰符static
  • 抽象修饰符abstract
  • 最终修饰符final
  • 同步修饰符synchronous
  • 本地修饰符native

类的构造函数

特殊之处:

  • 构造函数的方法名与类名相同
  • 构造函数没有返回类型
  • 构造函数的主要作用是完成对类对象的初始化工作

Java在声明类时,可以不定义构造函数,系统会自动为该类生成一个默认的构造函数,此时这个构造函数的名字与类名相同,没有任何形式参数,也不完成任何操作。

在创建一个类的新对象的同时,系统会自动调用该类的构造函数为新对象初始化。

类的访问控制符只有一个public

属性和方法的访问控制符有:

  • public
  • private
  • protected
  • private protected

对于同一个包中的类可以不需任何说明,方便的互相访问和引用。

在不同包中的类,只有他们都声明为public时,然后再在程序头部声明import后才可以被访问和引用相应的类。

publici修饰的类的属性称为公共属性,如果公共属性属于一个公共类,则可以被所有的其他类使用。

public修饰符会造成安全性和数据封装性下降,应尽量减少public属性的使用。

缺省访问控制符规定该类只能被同一个包中的类访问和引用,而不可以被其他包中的类引用,这种特性称为包访问性。

类内的属性和方法如果没有访问控制符来限定,也说明他们具有包访问性,可以被同一个包中的其他类所访问和调用。

用private修饰的属性或方法只能被该类自身所访问和修改,而不能被任何其他类,包括该类的子类来获取和引用。

procted修饰的属性可以被该类自身和包中的类访问。

静态属性

被static修饰的属性称为静态属性,静态属性是一个公共的存储单元。任何一个类的对象访问它时取到的都是相同的值,任何一个类的对象去修改它时,都是在对同一个内存单元做操作。

static修饰符修饰的属性是属于类的公共属性

static修饰符修饰的方法是属于整个类的方法

不用static修饰符修饰的方法是属于某个具体对象或实例的方法

声明一个方法的static至少有三重含义:

  • 调用这个方法时,应该使用类名做前缀,而不是某一个具体的对象名
  • 非static的方法是属于某个对象的方法,在这个对象创建时对象的方法在内存中拥有自己的专用代码段,而static的方法是属于整个类的,它在内存中的代码段将随着类的定义而分配和装载,不被任何一个对象专有。
  • static方法只能处理static类型的数据

静态初始化器

是由关键字static引导的一对大括号括起的语句组。

静态初始化器与构造函数的区别:
构造函数是对每个新创建的对象初始化,而静态初始化器是对每个类进行初始化。

构造函数是在用new运算符产生新对象时由系统自动执行,而静态初始化器则是在它所属的类加载入内存时由系统调用运行的。

不同于构造函数,静态初始化器不是方法,没有方法名,返回值和参数列表。

抽象类

当一个类被生命为abstract时,这个类被称为抽象类。

所谓抽象类就是没有具体实例对象的类。

抽象类是它所有子类的公共属性的集合。

使用抽象类的一大优点就是可以利用这些公共属性来提高开发和维护程序的效率。

最终类,最终属性,最终方法,终结器

  • 最终类

  • 如果一个类被final修饰符所修饰和限定,说明这个类不可能拥有子类

  • 最终属性

final就是用来修饰常量的修饰符,一个类的成员变量如果被声明为final,那么它的取值在程序的执行过程中都不会改变,也就是一个常量

用final修饰符说明常量时:

需要说明常量的数据类型

需要同时指出常量的具体取值

因为所有类的对象的常量成员,其数值都固定一致,为了节省空间,常量通常都被声明为static。

final修饰符所修饰的类方法,是功能和内部语句都不能被更改的最终方法,即是不能被当前类的子类重载的方法。

final方法固定所对应的具体操作,防止子类对父类关键方法的错误的重定义,保证了程序的安全性和正确性。

所有已被private修饰符限定为私有的方法,以及所包含在final类中的方法,都被缺省的认为是final的。

  • 终结器
  • 终结器是回收对象时执行的方法。

protected void finalize(){}

终结器是一个名为finalize的方法,没有产生列表和返回值。

volatile修饰符

被volatile修饰的类的属性可能同时被几个线程控制和修改,通常用来修饰受外部输入的属性。

本次的编程环境:

  • CentOS 6.8
  • Linux centos 2.6.32-573.8.1.el6.x86_64

在内核的源代码中定义了很多进程和进程调度相关的内容。其实Linux内核中所有关于进程的表示全都放在进程描述符这个庞大的结构体当中,关于这个结构体的内容和定义,可以在内核的linux/sched.h文件中找到。
现在就来通过编程实现对进程描述符的操作,主要是读取。至于修改等操作,将在后面的内容中提到。
通过对进程描述符的读取,可以获取进程的一切内容,包括进程的ID,进程的地址空间等等。

不多说,上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//20160912
//currentptr.c

#include <linux/tty.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/module.h>

/*Function To Write Msg To TTY*/
void tty_write_message(struct tty_struct *tty,char *msg){
if(tty && tty->ops->write){
tty->ops->write(tty,msg,strlen(msg));
}
return;
}

static int my_init(void){
char *msg="Hello tty!\n";
tty_write_message(current->signal->tty,msg);
printk("Hello -- from the kernel...\n");
printk("Parent pid: %d(%s)\n",current->parent->pid,current->parent->comm);
printk("Current pid: %d(%s)\n",current->pid,current->comm);
printk("Current fs: %d\n",current->fs);
printk("Current mm: %d\n",current->mm);
return 0;
}

static void my_cleanup(void){
printk("Goodbye -- from the kernel...\n");
}

module_init(my_init);
module_exit(my_cleanup);

以上的代码,主要就是通过引入内核头文件,进而引用进程描述符中的指针,并通过这种方式获取当前进程和相关进程的描述信息。
Makefile文件如下:

#Makefile
obj-m += currentptr.o

编译的指令:

make -C /usr/src/linux SUBDIRS=$PWD modules

然后通过insmod把模块装载进内核,首先tty输出了Hello tty!
同时在/var/log/message中,模块打印出了这些内容:

Sep 12 10:35:36 centos kernel: Hello -- from the kernel...
Sep 12 10:35:36 centos kernel: Parent  pid: 2235(bash)
Sep 12 10:35:36 centos kernel: Current pid: 13197(insmod)
Sep 12 10:35:36 centos kernel: Current fs: 927961856
Sep 12 10:35:36 centos kernel: Current mm: 932613056

分别是这个进程的相关信息。
对于进程描述符的定义,在本次实验用来编译的内核源码包(kernel-devel-2.6.32-642.4.2.el6.x86_64)中,
进程描述符具体定义在include/linux/sched.h的1326行往后。

需要参考的进程具体信息都在其中,可随时参考,以备不时之需。

Linux内核编程一直是我很想掌握的一个技能。如果问我为什么,我也说不上来。
也许是希望有一天自己的名字也出现在内核开发组的邮件列表里?或是内核发行文件的CREDITS上?
也许是吧。其实更多的,可能是对于底层的崇拜,以及对于内核的求索精神。
想到操作系统的繁杂,想到软件系统之间的衔接,内心觉得精妙的同时,更是深深的迷恋。
所以从这篇文章开始,我要真正的走进Linux内核里了,让代码指引我,去奇妙的世界一探究竟。

在这篇文章中,一起来对内核说Hello World。

本次的编程环境:

  • CentOS 6.8
  • Linux centos 2.6.32-573.8.1.el6.x86_64

没有安装内核的,可能需要安装一下内核源码包

  • kernel-devel-2.6.32-642.4.2.el6.x86_64

    yum install kernel-devel-2.6.32-642.4.2.el6.x86_64

安装好之后,这个版本内核可以在/usr/src/linux找到。

然后话不多说,首先看代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//20160904
//kernel_hello_world.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

static int __init lkp_init(void){
printk("Hello,World! --from the kernel space...\n");
return 0;
}

static void __exit lkp_cleanup(void){
printk("Goodbye,World! --leaving kernel space...");
}

module_init(lkp_init);
module_exit(lkp_cleanup);

以上代码是kernel_hello_world.c内容。
作为内核模块,在编译的时候,Makefile文件这样写:

1
2
#File:Makefile
obj-m += kernel_hello_world.o

然后可以通过这条命令来编译:

1
make -C /usr/src/linux SUBDIRS=$PWD modules

编译好以后,目录下面的文件可能是这样子:

kernel_hello_world.ko.unsigned  kernel_hello_world.o  Module.symvers
kernel_hello_world.c   kernel_hello_world.mod.c        Makefile
kernel_hello_world.ko  kernel_hello_world.mod.o        modules.order

有这么多文件被生成,其中kernel_hello_world.ko就是本次编译出来的内核模块文件,在Linux内核中有很多这样的模块,它们可能充当着不同的角色,可能是驱动,也可能是各种设备。

这个模块会在/var/log/message文件中打印一行字,即Hello,World! –from the kernel space…

可以使用insmod kernel_hello_world.ko来将这个模块载入到内核,使用lsmod来查看是否已经加载,使用rmmod kernel_hello_world.ko来卸载这个模块。

可以tail /var/log/message来看一下是否成功执行了呢?

Hello,Kernel.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×