colaghost

自己的世界。。。

archlinux下给cpu和显卡节能设置

最近在折腾archlinux,把内核更新到3.0后,发现A卡的官方驱动上不了了,只能上下开源的驱动了,无奈开源驱动的电源管理实在不敢恭维,笔记本键盘部分老是暴热,受不鸟。

下面就从cpu和显卡两个发热大户入手吧!

1、显卡降低频率

从内核2.6.35起就加入了AMD开源驱动的电源管理,可以进行GPU频率调整、显存频率调整、电压调整和温度监控支持等。

我的是A卡,这时候就发挥了它的作用了。

可以用如下命令查看当前显卡的电源管理模式:

$ cat /sys/class/drm/card0/device/power_profile

默认的是”default”,这个使用显卡默认频率不做调整。可以将它改为auto,low,mid,high等模式,auto可以根据当前是使用电池或者电源来自动做调整。这里我将它设置为low,注意有的本本设置为low可能导致部分显示问题。

# echo low > /sys/class/drm/card0/device/power_profile

注意这个设置只在当前运行时立即生效,要在下次启动时也有效的话可以手动将它加进/etc/rc.local配置文件里。

2、CPU动态调节频率功能

查了下有cpufrequtils这个小工具,可以实现自动/手动调节CPU频率,对于笔记本来说是很有用的。

通过pacman安装即可。

$ pacman -S cpufrequtils

安装完后先手动加载驱动。

# modprobe acpi-cpufreq

为了下次启动时自动加载可以把它加到/etc/rc.conf配置文件的MODULES列。

加载完驱动后,可以执行cpureq-info查看下cpu信息。

cpufreq提供了好几个电源调整方案,我用的是cpufreq_ondemand,这个可以根据系统负载动态调整CPU频率,这个也需要加入/etc/rc.conf的MODULES列里。

最后还需要配置下/etc/rc.d/cpufreq,将#governor=”ondemand”那句取消注释后保存即可。

设置好配置文件后,可以运行以下命令来启动守护进程:

# /etc/rc.d/cpufreq start

启动后再执行下cpufreq-info看看当前频率是不是已经降下来了!

若要在启动时自动守护进程,要将cpufreq加入/etc/rc.conf配置文件的DEAMONS列里。

总结

这样设置后温度大概会比原来降低十度左右,不过貌似还是没有安装闭源驱动fglrx时温度低,但总算没那么烫手了!

UC小记

到uc上班已经一个半月了,貌似打酱油的成分比较多, 这里说一下自己的感受吧。

氛围

技术氛围比较好,平时吃饭、中午休息时都会遇到一些同学(UC是大五文化,同事间称同学~)激烈的讨论声,这让我一次跟入职指引人笑说UC的技术讨论火药味比较重!

部门研发经理和主管都在我这边,没有什么上下级概念。对研发经理的印象最好了,当时面试我的就是他,脸上一直有笑容,平时一起吃饭时也总是笑着说话,让我感觉很舒服。

python

当时一直跟一个在UC的同学笑说内推我去UC写Python好了,没想到现在真的实现了。

得益于python的简洁性,工作时上手会快一些。要是是纯C++,光是了解语言特性本身就是一个挺高的门槛了。虽说总是自从为C++学得不错,像模板啊、对象模型这些都了解得不错,但是真看起一些国外的C++写的开源包,有时候还是被一些用法弄得糊里糊涂的。

小红花

小红花就差不多是一种鼓励、感谢的象征吧,这是UC文化的一部分。当你想鼓励一个人,或者别人在工作上(也可以是其他的)帮助了你,你就可以贴一朵小红花(写上原因)在他的办公桌上。

说真的,当时觉得这玩意儿有点傻,看旁边的人也都没有怎么动过这些东西,也就一直扔在桌旁一角。有一天上班时,竟然发现被贴了一朵小红花。当时还在YY是哪个女的贴的,看了一下才知道是小组主管贴的,说在最近的项目任务上完成得不错,上手很快,有点飘飘然的感觉了。

分享会

这个对我来说还是比较新鲜的,之前实习时一直没有这样类似的会议。

分享是局部于部门内,一周一次,小组里的每周轮流确定分享的技术心得。分享的人可能会辛苦点,因为可能随时被打乱,回答别人的疑问或者是听取别人的见解,往往是口头说得不爽了就动手了,直接拿起笔在白板上画,最后画的总会被XX得乱七八糟。

迷惑

貌似感觉这个半个月来进展很慢,没有方向,每天看看文档,看看代码,却发觉没有一个具体的目标,代码很多也看不懂,只能一边坚持看着,一边google下有没有相关的文档,很多时候找到的都是英文的,说句不好听的真的是看英文看到想吐了。

有一个感觉就是在一个小的范围内,如线程管理,假设集中于阅读这一方面的代码,能够很有sense,最终在小组某些同学的帮助下也大概能看懂。但是假设范围拉得太宽,没有一个集中的点,往往是搞了半天不知所云。想要集中一个方向,却发现在没有其他人的指引下一时找不到前进的方向,这让我相当迷惑和纠结。

也许我应该主动点,一个人看文档和看代码太闷,往往也会因为看不懂而看不下去,应该主动寻求其他同学的帮助,让入职引领人给我做一 些关于系统模块和各个流程的讲解,这样再来看代码,或许会更有效。

一个典型的Twisted服务端应用程序

简介

一个典型的twisted服务端应用程序一般包括三部分,分别是协议、工厂和启动服务器,其中协议负责接管建立连接后的工作,包括收发数据和决定是否关闭连接等;工厂的工作是管理连接事件。

这里是通过继承Twisted中的一些类来实现的!

基本框架

导入部分

这部分主要是供协议类和工厂类使用的

1
2
from twisted.internet import protocol
from twisted.protocols import baisc

协议

继承自basic.LineReceiver,可以进行行和原始数据两种方式的接收处理。

1
2
3
4
5
6
7
class Answer(LineReceiver):
    def lineReceived(self, line):
        #行数据接收处理方式
        pass
    def dataReceived(self, data):
        #原始数据接收处理方式
        pass

工厂

继承自protocol.ServerFactory。

1
2
3
4
5
6
7
8
9
10
11
12
class AnswerServerFactory(protocol.ServerFactory):
    protocol=Answer#表明每次成功建立连接时要实例的协议类型
    def startFactory(self):
        #在开始监听一个端口或连接器时被调用
        pass
    def stopFactory(self):
        #在停止监听所有端口或连接器时被调用
        pass
    def  buildProtocol(self, addr):
        #实例化Protocol的子类
        protocol.ServerFactory.buildProtocol(self, add)
        pass

启动服务器

1
2
3
from twisted.internet import reactor
reactor.listenTCP(8000,AnswerServerFactory())
reactor.run()

其中reactor是一个反应器,它主要用于实现事件循环,除了分发事件循环之外,还需做:定时任务、线程、建立网络连接和监听连接等。

ubuntu下自动切换声音输出设备

我有一个usb耳机,在ubuntu下驱动也正常,不过有一个蛋疼的地方就是每次插进usb耳机都不会自动切换到usb耳机对应的声音输出设备,次次都要手动去选择对应的,于是想着能不能写一个脚本来实现。
不过貌似关于这方面的中文资料不多,google了很久都没有什么结果,倒是找出一个freebsd上能实现的,就是sysctl,不过貌似ubuntu下实现不了。后来在stackoverflow上问老外才得知用pacmd可以列出各种可用的声音输出设备还有设置默认输出设备等操作神马的。
弄了一下,果真OK了,写随意写了一个脚本来测试了,这个脚本假设系统使用pulseaudio的。
原理也不难,就是检测所有的声音设备,找出当前默认的声音设备,然后把声音设备切换到下一个,重新运行脚本就可以把声音设备切换回原来默认的了。

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
#!/bin/bash
 
declare -i count=`pacmd list-sinks | grep -c index:[[:space:]][[:digit:]]`
declare -i active=`pacmd list-sinks | sed -n -e 's/\*[[:space:]]index:[[:space:]]\([[:digit:]]\)/\1/p'`
declare -i major=$count-1
declare -i next=0
 
if [ $active -ne $major ] ; then
next=active+1
fi
 
pacmd "set-default-sink ${next}"
 
for app in $(pacmd list-sink-inputs | sed -n -e 's/index:[[:space:]]\([[:digit:]]\)/\1/p');
do
pacmd "move-sink-input $app $next"
done
 
declare -i ndx=0
pacmd list-sinks | sed -n -e 's/device.description[[:space:]]=[[:space:]]"\(.*\)"/\1/p' | while read line;
do
if [ $next -eq $ndx ] ; then
notify-send -i notification-audio-volume-high "声音输出切换到" "$line"
exit
fi
ndx+=1
done;

脚本里在切换后会做notify-send的提示,假设找不到命令的可以执行sudo apt-get install libnotify-bin安装一下,但不安装也没有什么关系,只是一个提示而已。

为了方便可以将脚本复制到/usr/bin目录下,然后在“键盘快捷键”里面添加多一个快捷键,命令就是脚本名了,最后设定好想要的快捷键,以后就可以直接切换了。

ubuntu下看flash视频时禁用屏保

最近两天在啃《unix环境高级编程》,一直转在ubuntu下。我吃饭时喜欢一边看电影,可是上优酷看flash视频时又有一个麻烦的地方,就是屏保并不会自动被禁用掉,而是得手动去禁用,看完又得去把它开启,甚是麻烦,就想着自己写一个脚本来实现开启/禁用屏保。

Google了下,关于这方面的结果倒是不少,下面是其中一个脚本:

1
2
3
4
5
6
7
8
#!/bin/sh
while true;
do
    if test -n "`file /tmp/Flash*|grep \"Macromedia Flash Video\\|MPEG v4\"`";then
        gnome-screensaver-command -p
    fi
    sleep 30
done

可惜我发现我的tmp目录下并不会生成/tmp/Flash*,我原先以为是我用shockwave flash的原因,不是在tmp目录下生成缓存。就自己搜索任何可能的目录,看下具体在哪个目录里生成缓存,可惜找不到。

这时候想到linux下是可以通过lsof来监测某一个进程当前打开了哪些文件,结果发现了其实是有在/tmp目录下生成Flash*这样的文件的,只是生成后马上又被删除了,这时候虽说进程还可以进行读写操作,可是在目录下却无法看到。

因此想到了另外一种方法,由于shockwave flash做为chrome下的一个插件,只要监测到chrome载入libgcflashplayer.so的这一个进程打开的所有文件下有/tmp/Flash*类似的文件即可知道当前在播放flash视频,这时候只要运行”gnome-screensaver-commad -p”模拟活动一下即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
while true;
do
	pid=`ps aux | grep /opt/google/chrome/libgcflashplayer.so | grep -v grep | awk '{print $2}'`
	if [ "$pid" != "" ]; then
		data=`lsof -p $pid | grep /tmp/Flash`
		if [ "$data" != "" ]; then
			echo "gnome-screensaver-command"
			gnome-screensaver-command -p
		fi
	fi
	sleep 30
done

深信服实习结束

两个月的期限到了,公司其实鼓励我们继续实习下去,但是接下去学校的一些事,加上一些累的情绪,还是早早选择回校了。这里说下两个月来的感受吧。

氛围

跟之前了解的一样,深信服从观念上有点类似于硅谷的企业,比较平民化,相对自由,没有明显的上下级观念,大家都是直呼名字,就算是主管人家也会拿来开玩笑,不要求应届生一定要拿到毕业证,上班不需要打卡,主管神马的都没有独立的办公室,甚至RDM的人都跟我们AC产品部门的在同一个大厅里,只是办公位置相对分隔开而已。

公司创始人来源于华为,这个对公司的加班文化有很大影响,高层总是强调危机感,强调现在还达不到不用加班就能保持竞争力的地步。我们现在周一、二、四都是要加班的,周末的话也是隔周就要上半天。很多人其实对这个硬性规定不爽的,其实我觉得可以放开这条规定,毕竟很多人其实都很拼周一到周五都会留到很晚才回去,硬性规定给人感觉上多多少少有点不信任的感觉。

定制

这是我所在部门的小组,其实就是满足客户一些特殊需求在正式版本上添加一些小功能,每个任务周期都很短,一般都是一个星期左右。

这个小组是部门里做的活最杂最累的,任务多,接触面杂,从linux底层驱动到前端js都有可能让你做。不过也拜这个所赐,让我在短短两个月里接触了js、php和CGI等,虽说比较分散,但从一定程度上拓宽了我的水平。也是从这里才开始明白,其实用什么语言写程序并不重要,更重要的是你的思路,你分析问题的能力,还有你的学习能力。

我导师有时候说,在定制组还是有好处的,以前不会去做的东西现在都做了,绩效也好写,毕竟做的任务多,随便一拈都有不少。当然这个也有玩笑的成分在,不过对于刚来的人还是有一定好处的,不会让自己限死在一个方向和模块。

注重

由于之前公司可能更多考虑的是生存,部门产品的旧版本代码实现比较乱,注重功能,却忽视了后期的可维护性。这貌似是很多新员工刚来纠结的问题,一个函数可以写上千行,然后不加一句注释,这不是让人吐血么?有能力做到一秒钟处理10G流量的数据包,却不愿意多写几行注释,不写注释害死后来者啊。不过现在公司也在开始考虑这个问题了,也有专门的小组在重构整个产品的代码了,不过三百万行级的代码量,似乎还没加上底层驱动,估计也得耗费很长一段时间。

学习

在深信服每个人成长都很快,这跟压力有关,也跟公司的技术和规模快速发展有关。

深信服貌似在技术培训上比较少,更多是依赖于个人的自己学习和与周边人的交流分享。

公司有内部自己的类似于技术文刊那样子的东西,主要都是重大技术突破、编码经验和一些创新点上的东西。产品每个核心模块都会录制相关视频,讲解它的设计,主要数据结构跟运用算法等等东西。

我们部门的副主管弄了一个AC产品知识库,主要是面向于新员工,里面包含了培训文档、员工成长练习题库,以及产品周边的各种基本知识PPT和产品用到的各种技术文档,甚至还有CGI的编写和LINUX驱动开发规范等。

公司里所有的核心技术跟代码都毫无保留地向所有员工公开,这点个人觉得做得比较好,你对哪块有兴趣你都可以自己拿代码跟文档去研究,公司也倾向于培养各个模块的专家,以便有人接手各个模块。

用expect来实现自动交互的shell脚本

有时候可能实现自动交互过程,如自动登陆到远程主机等,由于需要输入用户名密码神马的,得自己呆在那里等它登陆完成,比较麻烦,单纯用shell脚本又没法完成,因为像ssh连接远程主机是不从stdin读入数据的。这时候就需要expect出马了。

Expect是基于TCL的,作为一个脚本语言,expect能在无需管理员参与的情况下实现自动交互(比如passwd,fsck,telnet等),expect也能用于自动测试一些应用程序。

搜索一下其实网上很多使用expect来完成密码登陆的例子的:

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
auto_login_ssh () {
    expect -c "set timeout -1;
                spawn -noecho ssh -o StrictHostKeyChecking=no $2 ${@:3};
                expect *assword:*;
                send -- $1\r;
                interact;";
}
 
auto_login_ssh passwd user@

但实际上这个脚本不能做到完全自动化,一旦密码错误或者远程主机未响应神马的,expect还是正常退出,并不能判断到底哪一步出问题了。由于使用expect后,程序的exit status是expect的,所以这时候对expect做处理。当expect遇不到期望的输出值时,就会执行eof分支,这时候我们只要在eof分支加上退出值即可以判定到底是在哪一步出了问题。

这里用两个简单的脚本说明,这样比较容易弄清楚。

called.sh

1
2
#!/bin/bash
echo "a"

可以看出上述脚本是输出“a”,也就是期望输出值应该为”a”。下面看用expect实现的交互脚本:
caller.sh

1
2
3
4
5
6
7
8
9
#!/bin/sh
expect -c "set timeout -1;
           spawn called.sh;
           expect{
               \"b\"{exit 1;}
               eof{exit 2;}
           }
           "
echo $?

实际上called.sh的输出值是”a”,但caller.sh的期望值为”b”,这时候实际上是跳到eof,这时候按状态2退出,也就是说$?实际上为2.这时候就可以判断交互脚本具体的执行情况。

这里只是一个简单的实例而已,并没有任何实际的意义,但是它说明了如何处理一些异常的情况,这样只要将上面的自动完成ssh连接远程主机的脚本加上异常情况处理即可变成一个真正完全自动交互的脚本了,以下是做修改后的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
auto_smart_ssh () {
    expect -c "set timeout -1;
                spawn ssh -o StrictHostKeyChecking=no $2 ${@:3};
                expect {
                    *assword:* {send -- $1\r;
                                 expect {
                                    *denied* {exit 2;}
                                    eof
                                 }
                    }
                    eof         {exit 1;}
                }
                "
    return $?
}
 
auto_smart_ssh passwd user@host ls /var
echo -e "\n---Exit Status: $?"

注:以上自动完成ssh连接远程主机例子来自于apt-blog.net

初到深圳

到深圳

到深圳实习,那天是八点的车,和另外一个同学一起过来的。最讨厌坐太早的车了,不过订时说只有八点的,神马玩意儿。车比较破,关键是半路上还有人吐了,整辆车都是那味道,唉~

在南头检查站那下车了,下车地点有一个公车站,深圳的公车站明显不够广州的霸气,这个甚至还没有任何车站的信息,杯具!一直在那里茫然,后来才发现马路对面有一个公车总站,那里才有车到科技园。

要先到公司那去,有人接待我们并带我们去住的地方。梁教主运气好上午到已经有人带他们先过去公寓了,不过幸好他们了,公寓满了,我们跟市场部的住一起,住三星级的酒店。

入职

15号正式入职。填完实习协议神马的HR就一个个带到分配去的部门,我运气好,跟另外一个分到AC的定制组,这是全部门做的东西最杂最累的小组。主要做的就是根据用户的需求在原有产品上加入一些功能,这要求你看懂别人的代码并修改,而且从前端到linux底层驱动都有可能接触;通常周期也短,都是一两个礼拜完成一个项目。

公司周一、二、四都要加班到九点,一个月也有两个周六是要上半天班的,不打卡,吃饭时是根据你录入的指纹的。

实习时比较好,吃饭、住宿,甚至坐车公司都会帮你出钱,基本上就是纯粹过来赚钱的,只要你好好工作就行了。

住宿

公司提供住的地方,这算是深信服一个比较好的地方吧,因为过来的话假设自己租房很难租到短期房,而且很多人刚过来时都人生地不熟的。

其实研发住的地方是在一个小区里租的房子,公司好像将里面改过了,里面是一个大房间,又分成六间小房,一个小房睡两个人。

我们几个那天运气好,公寓住满了,所以让我们过去宝安一个酒店跟市场的住一块,不过貌似只能住到三月十四号,到时候就搬回公寓。

吃饭

公司里提供三餐,自助式的,实习时都不用自己花钱,正式时要自己出十块钱来付午餐加晚餐。但是很抵啦,自己打菜,爱打多少打多少,也很合我的口味,像我这么挑食的都觉得好吃了,别人更不用说了。

感觉

深圳这个城市并不难适应吧,也许南方城市都比较像,对于我这种没踏出过省半步的人都比较容易适应。

每天早出晚归,好像有点怀念大学的美好时光了。周围的人都很年轻很牛,可是都很努力在工作,我有点感慨,当初选择深信服,不就是为了年轻时多努力奋斗点吗?

其实我要求的并不多,只是希望需要的人在身边,也许我这人很恋家,因为我知道家庭很平凡,但往往越平凡的东西有时候可能越难得到。

缓冲区溢出攻击实验

使用系统环境为:ubuntu10.04 2.6.32-27-generic gcc4.4.3
这里先放出实验代码:

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
#include <stdio.h> 
#include <stdlib.h>
#include  <ctype.h>
 
char *getxs(char *dest)
{
	int c;
	int even = 1;
	int otherd = 0;
	char *sp = dest;
	while ((c=getchar())!=EOF&&c!='\n')
	{
		if (isxdigit(c))
		{
			int val;
			if ('0'<=c&&c<='9')
				val = c - '0';
			else
				if ('A'<=c&&c<='F')
					val = c - 'A' +  10;
			else
				val = c - 'a' + 10;
			if (even)
			{
				otherd = val;
				even = 0;
			}
			else
			{
				*sp   = otherd*16 + val;
				even = 1;
			}
		}
	}
//	*sp   = '\0';
	return dest;}
 
int getbuf()
{
	char buf[12];
	getxs(buf);
	return 1;
}
 
void test()
{
	int val;
	printf("Type Hex string:");
	val = getbuf();
	printf("getbuf returned 0x%x\n", val);
}
int main()
{
	int buf[16];
	int offset = (((int)buf)&0xfff);
	int *space = (int*)alloca(offset);
	*space = 0;
	test();
	return 0;
}

其实这是《深入理解计算机系统》里的一个家庭作业,根据以上代码可以看出getbuf()函数在正常情况下无论怎么调用都会返回值1。任务是只简单地对提示符输入一个适当的十六进制字符串,就使getbuf对rest返回-559038737(0xdeadbeef)。
不过在目前的内核和编译器下要直接对原程序进行栈溢出攻击是不可能完成的了。现在的编译器对代码做了一些防止溢出攻击的保护措施,如%gs:0×14。每次运行程序时它都会随机产生一个类似验证码的值,当函数返回时它会验证此验证码是否被改变,由于它验证码的存放内存位置位于buf数组和保存在栈上的%ebp之间,只要数组一旦越界写入的话就会被改变,这时候也会触使保护代码运行。
不过我在编译时加进了-fno-stack-protector选项,这时候是不产生任何栈溢出保护代码的。
以下是源程序反汇编所得的主要汇编代码:

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
08048569 :
 8048569:	55                   	push   %ebp
 804856a:	89 e5                	mov    %esp,%ebp
 804856c:	83 ec 28             	sub    $0x28,%esp
 804856f:	8d 45 ec             	lea    -0x14(%ebp),%eax
 8048572:	89 04 24             	mov    %eax,(%esp)
 8048575:	e8 2a ff ff ff       	call   80484a4
 804857a:	b8 01 00 00 00       	mov    $0x1,%eax
 804857f:	c9                   	leave
 8048580:	c3                   	ret    
 
08048581 :
 8048581:	55                   	push   %ebp
 8048582:	89 e5                	mov    %esp,%ebp
 8048584:	83 ec 28             	sub    $0x28,%esp
 8048587:	b8 e0 86 04 08       	mov    $0x80486e0,%eax
 804858c:	89 04 24             	mov    %eax,(%esp)
 804858f:	e8 38 fe ff ff       	call   80483cc
 
 8048594:	e8 d0 ff ff ff       	call   8048569
 8048599:	89 45 f4             	mov    %eax,-0xc(%ebp)
 804859c:	b8 f1 86 04 08       	mov    $0x80486f1,%eax
 80485a1:	8b 55 f4             	mov    -0xc(%ebp),%edx
 80485a4:	89 54 24 04          	mov    %edx,0x4(%esp)
 80485a8:	89 04 24             	mov    %eax,(%esp)
 80485ab:	e8 1c fe ff ff       	call   80483cc
 
 80485b0:	c7 04 24 07 87 04 08 	movl   $0x8048707,(%esp)
 80485b7:	e8 20 fe ff ff       	call   80483dc
 
 80485bc:	c9                   	leave
 80485bd:	c3                   	ret

这里主要需要进行getbuf和test两个函数汇编代码的分析。
分析可以得出:test调用了getbuf函数,getbuf将0×1传送到%eax做为返回值。test将返回值赋值给val,最后以16进制打印出来,这个结果在正常情况下无论如何就只是输出0×1。
这里通过汇编代码我们可以发现两种思路,一种就是在getbuf中输入字符串时,覆盖栈中保存的%ebp值(跟原先的值一样),返回地址(使其直接跳转到test汇编代码的call 80483cc 这一句,以及返回地址上面的8个字节%ebp+4、%ebp+8(这两个是做为printf的两个参数);另外一种就是往buf里注入一段机器码(这段机器码主要是将%eax赋值为0xdeadbeef),当然这时候也需要覆盖返回地址,使其跳转到注入的机器码的起始地址,不过这种方法在目前的内核下并不可行,会引发系统某种保护机制而失败。
这里主要研究第一种思路,下面可以看下test和getbuf的部分栈的组织图。

getbuf里分配了40个字节的空间,不明白为什么需要这么多额外的。
这里主要需要获取%ebp的值,以及call 80483cc 这一句的地址(这个可以从汇编代码里得出为0×80485ab)。
%ebp的值需要调试运行在getbuf函数里面下断点读出。
用gdb调试过程如下:
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3 : GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type “show copying”
and “show warranty” for details.
This GDB was configured as “i486-linux-gnu”.
For bug reporting instructions, please see:

Reading symbols from /home/colaghost/Desktop/test2…done.
(gdb) break *0×804856c
Breakpoint 1 at 0×804856c: file test.c, line 42.
(gdb) r
Starting program: /home/colaghost/Desktop/test2
Breakpoint 1, 0×0804856c in getbuf () at test.c:42
warning: Source file is more recent than executable.
42 {
(gdb) print /x *(int*)($ebp)
$1 = 0xbfffefd8
这里得出保存的%ebp值为0xbfffefd8,下面可以得出要返回0xdeadbeef的字符串。
首先是输入任意40个十六进制字符填满char[12]和额外的8个字节,继续输入保存的%ebp的值,返回地址0×80485ab,printf的第一个参数的存放地址,即 0×80486f1,最后是我们要打印的字符0xdeadbeef。
最终得到的字符串就是这样的:
b8ef bead deba 6985 0408 ffe2 0000 0000 0000 0000 d8ef ffbf ab85 0408 f186 0408 efbe adde
后记:最先由于%gs:0×14,以及系统的一些保护机制,在正确的思路下花费了一整晚的时间都没有任何进展,一直是以sementation fault告终。第二天上午在gdb调试运行状态下才算成功得到返回值。输入同样的字符串,在gdb运行状态下可以得到返回值,并且显示程序正确结束;不过在一般运行状态下test方法返回后一直出现sementation fault的错误,到现在都未找到实际原因。

儿童绘画的动感世界

前言

当初做这个东东只是想参加学校的科研立项,最初的设想是供儿童随意在画板上涂鸦,然后让儿童涂鸦的图案动起来,就例如说画一个球就会滚动,画一辆飞机就会飞起来。

前期

当初的设想很美好很强大,但真正构思时却发现这远远超出了我们的水平,光是基本图形,如直线,多边形,圆等的识别就已经让我们纠结了好久。

但既然选择了,无论做成什么样,还是要继续下去的。我们团队几个人开始研究关于基本图形的识别,记得大概好像耗费了一个月的时间吧。当时首先解决的是关于直线的识别,其实说起来也很简单,就是计算首末两点的距离,和整条直线点与点之间距离的和,前者除以后者,当结果大于某一个常数时就认为是直线。经过测试也认为这是可行的,识别率在经过不断调整那个常数后可以达到很高了,差不多90%以上了。

后来圆、多边形以及波浪线跟弧线的识别也都一一被攻破,当时还用MFC做了一个很简陋的画板来测试这些方法,可惜那个画板好像后来删掉了。

但光识别基本图形还不够,毕竟不可能只画这几样东西。我们做了一个设想,就是认定所有的图形,无论多复杂,都是由这些基本图形构成,只要我们能够统计出一幅图案由多少种基本图形构成,以及各种基本形的个数和它们的相对位置,即可以认定为它是或接近于哪幅图案。当然图案都由我们收集好,目前我们做不到说儿童想要画什么就出现什么样的动画,只能通过播放接近的flash来实现这个目的。图案也就是flash,我们收集了几百种flash,并统计他们的特征,也就是上面说的那几个值,并以特定的方式编写好一个配置脚本,识别时就是根据这个配置脚本来判定的(基本图形除外)。

正式版本

这个版本的界面就是上图,很简单,只有几个按钮,如清除画面,识别画图,截图和退出等。因为这是面向儿童的,觉得不应该有太多操作,应该尽可能简单,涂鸦时也不可选定画线大小和颜色等,这不是普通的画板!

下面两张图片是一个简单的示例:

涂鸦

涂鸦

识别后

识别后

其实这里有一个问题,就是基本图形只能一笔画完,不然就会被认定为其它基本元素。组合识别有时候也不是尽善人意,会出来一些令你摸不着头脑的动画。

最后

这里做得比较成功的还是关于基本图形的识别吧,至少可以保证很高的识别率,大都在90%以上。组合识别却有待改进,或者我们应该改变整个识别的思路,但至于怎么做,我们现在却都没有时间去考虑了,接下去都是要工作了,也许将来有时间和有能力来改善这个版本,我相信会是一个很好的东东。至少,它让你的构思动起来了,这不是很好玩吗?