一直都是在学习理论。没有实实在在的调试一个无源码软件。看到很多朋友的分析了一个扫雷的游戏。就在网上搜索了一个GTK的扫雷的游戏...自己也分析分析一下...实际上机器里面有这个游戏。但是没有源码.....为什么要找有源码的呢....呵呵。实际上是怕自己第一次分析。如果分析不出来,呵呵...准备一下。
开始:
哦,对了我的目标是给他些个外挂....不是最近外挂比较流行嘛。跟风.......
编译了获得ELF
代码:
[jun@beijihuCom mines]$ gcc mines.c -o mines `pkg-config --cflags --libs gtk+-2.0`
![](78243/546516/21280.jpg)
首先反汇编分析一下...想到的idal但他的操作实在是不习惯。以后好好的适应一下...毕竟人家可是传说中可以买到的最好的反汇编利器....
我的原始方法...objdump
先反汇编了再说
代码:
[jun@beijihuCom mines]$ objdump -d ./mines > mines.asm
代码:
[jun@beijihuCom mines]$ objdump -s ./mines >mines.text
看下我们的字符文件。界面上有个reload。这个按钮是用来重新开始的...重新开始必定要重新布雷.一定会有相关布雷的信息.....
一起看看mines.text....
代码:
....... Contents of section .rodata: 804a024 03000000 01000200 00000000 cddba3a1 ................ 804a034 c4e3d5e2 c3b4c5a3 a3acd3c3 cab12025 .............. % 804a044 336420c3 eba1a300 ccabd3d0 b2c5c1cb 3d ............. 804a054 a3a1d5e2 c3b4bfec becdcde6 cdeac1cb ................ 804a064 a1aba1ab 00200000 2564002a 00313000 ..... ..%d.*.10. 804a074 a3a10064 656c6574 655f6576 656e7400 ...delete_event. 804a084 72656c6f 6164004d 696e6573 3a005469 reload.Mines:.Ti 804a094 6d653a00 30006361 6e2d666f 63757300 me:.0.can-focus. 804a0a4 62757474 6f6e2d70 72657373 2d657665 button-press-eve 804a0b4 6e740063 6c69636b 656400 nt.clicked. .......
位于0x804a0b7 有clicked 是用来连接按钮的 "clicked" 信号到回调函数的字符...
再到 mines.asm..... 看看....查一下0x804a084
代码:
8049aae: 89 04 24 mov %eax,(%esp) 8049ab1: e8 be f0 ff ff call 8048b74 <g_signal_connect_data@plt> 8049ab6: c7 04 24 84 a0 04 08 movl $0x804a084,(%esp) 8049abd: e8 62 f1 ff ff call 8048c24 <gtk_button_new_with_label@plt> 8049ac2: a3 d4 b2 04 08 mov %eax,0x804b2d4 8049ac7: a1 d4 b2 04 08 mov 0x804b2d4,%eax 8049acc: c7 44 24 08 1c 00 00 movl $0x1c,0x8(%esp)
代码:
movl $0x804a084,(%esp)
会保存在%eax里面...指针被保存到0x804b2d4
和那个0x804a0b7 "clicked" 信号
下面我们应该找到那个会调函数了..作用应该就是重新布雷了...
代码:
8049ef6: bb 81 95 04 08 mov $0x8049581,%ebx ------------------------------------beijihu's split-line---------------------------------------------- 8049efb: e8 34 ec ff ff call 8048b34 <gtk_object_get_type@plt> 8049f00: 89 c2 mov %eax,%edx 8049f02: a1 d4 b2 04 08 mov 0x804b2d4,%eax 8049f07: 89 54 24 04 mov %edx,0x4(%esp) 8049f0b: 89 04 24 mov %eax,(%esp) 8049f0e: e8 71 ec ff ff call 8048b84 <g_type_check_instance_cast@plt> ------------------------------------beijihu's split-line---------------------------------------------- 8049f13: c7 44 24 14 00 00 00 movl $0x0,0x14(%esp) 8049f1a: 00 8049f1b: c7 44 24 10 00 00 00 movl $0x0,0x10(%esp) 8049f22: 00 8049f23: c7 44 24 0c 00 00 00 movl $0x0,0xc(%esp) 8049f2a: 00 8049f2b: 89 5c 24 08 mov %ebx,0x8(%esp) 8049f2f: c7 44 24 04 b7 a0 04 movl $0x804a0b7,0x4(%esp) 8049f36: 08 8049f37: 89 04 24 mov %eax,(%esp) 8049f3a: e8 35 ec ff ff call 8048b74 <g_signal_connect_data@plt>
还记得0x804b2d4放的什么吗? 是的,按钮的句柄。
0x804b2d4 是 g_type_check_instance_cast的参数,检测起对象的类型的正确性,返回到对象的指针到%eax实际上和强制转换有点像。
第二个分割线下面是是信号接受的函数调用,这个和masm编译的的调用有点不大一样,但是仍然是栈在传递函数,也是"c"的调用方式从右向左...
我们看到%ebx里放着回调函数的的地址....向上找找,在第一个分割线上面我们看到了会调函数的地址。
我们来到了这个地方
代码:
08049581 <g_reset>: 8049581: 55 push %ebp 8049582: 89 e5 mov %esp,%ebp 8049584: 83 ec 08 sub $0x8,%esp ........
我们根据他调用的函数猜解一下这个函数大致的意思....
<gtk_label_get_type@plt> 标签的类型
<g_type_check_instance_cast@plt> 对象检查
<gtk_label_set_text@plt> 设置标签的显示....
下面一个 jmp 到跳转的地方一个比较一个jl 跳转,显然是一个循环。不会布雷就在这里吧...继续看..
大致的看了俄看循环体里的代码甚至没有随即数的生成,不对,不会是布雷。更像是清理战场.....
果然在下面我们看到一个函数 <put_mines> 从字面上都可以看出来是布雷了。程序员们使得自己的程序易读的同时也方便了反编译的朋友们了...
代码:
08049056 <put_mines>: 8049056: 55 push %ebp 8049057: 89 e5 mov %esp,%ebp 8049059: 83 ec 18 sub $0x18,%esp 804905c: e9 09 02 00 00 jmp 804926a <put_mines+0x214> 8049061: a1 f0 b2 04 08 mov 0x804b2f0,%eax 8049066: 89 44 24 04 mov %eax,0x4(%esp) 804906a: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8049071: e8 5e fb ff ff call 8048bd4 <g_random_int_range@plt> 8049076: 89 45 f4 mov %eax,0xfffffff4(%ebp) 8049079: 8b 55 f4 mov 0xfffffff4(%ebp),%edx 804907c: 89 d0 mov %edx,%eax 804907e: c1 e0 02 shl $0x2,%eax 8049081: 01 d0 add %edx,%eax 8049083: c1 e0 02 shl $0x2,%eax 8049086: 89 c2 mov %eax,%edx 8049088: a1 c4 b2 04 08 mov 0x804b2c4,%eax 804908d: 8d 04 02 lea (%edx,%eax,1),%eax 8049090: 8b 40 04 mov 0x4(%eax),%eax 8049093: 83 f8 01 cmp $0x1,%eax 8049096: 0f 84 ce 01 00 00 je 804926a <put_mines+0x214> 804909c: 8b 55 f4 mov 0xfffffff4(%ebp),%edx ........ 8049270: a1 b0 b2 04 08 mov 0x804b2b0,%eax 8049275: 39 c2 cmp %eax,%edx 8049277: 0f 8c e4 fd ff ff jl 8049061 <put_mines+0xb> 804927d: c9 leave 804927e: c3 ret
我们只需要了解到他的雷布完以后会保存到哪.....
实在是麻烦分析了好一会,也没有把数据结构的地址搞出来。还是动态调试一下吧.
但是我们已经知道了是
代码:
(gdb) b put_mines Breakpoint 1 at 0x804905c (gdb) r ....... [Thread debugging using libthread_db enabled] [New Thread -1208604992 (LWP 15246)] [Switching to Thread -1208604992 (LWP 15246)] Breakpoint 1, 0x0804905c in put_mines () (gdb) stepi 0x0804926a in put_mines () //单步到8048bd4 (gdb) ...... (gdb) 0x08048bd4 in g_random_int_range@plt () (gdb) next Single stepping until exit from function g_random_int_range@plt, which has no line number information. 0x03b29f40 in g_random_int_range () from /lib/libglib-2.0.so.0 (gdb) next Single stepping until exit from function g_random_int_range, which has no line number information. 0x08049076 in put_mines () (gdb) info r eax 0x54 84 //返回一个随机数84 ecx 0x85c57e0 140269536 edx 0x0 0 ebx 0x3c16674 63006324 esp 0xbfb41170 0xbfb41170 ebp 0xbfb41188 0xbfb41188 esi 0x8049581 134518145 edi 0x85e2d68 140389736 eip 0x8049076 0x8049076 <put_mines+32> eflags 0x246 [ PF ZF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) c Continuing.
一直在猜想这一段的代码是作什么的,后来搜索了一下 804b2c4 这个数字,发现他很多时候出现都会伴随着lea (%edx,%eax,1),%eax 这样一个操作,应该存放着的是一个基地址,用来寻址操作的,只是猜想,我简单的翻译了一下这一段代码
代码:
mov %eax,0xfffffff4(%ebp) //%eax 保存的是随机数 mov 0xfffffff4(%ebp),%edx mov %edx,%eax shl $0x2,%eax add %edx,%eax shl $0x2,%eax mov %eax,%edx // %edx=(%eax*4+%eax)*4 相当于 随即数乘以了一个20 mov 0x804b2c4,%eax // 是在0x804b2c4的地址处取值。 lea (%edx,%eax,1),%eax // %eax=%edx+%eax*1 用取得的值加上随机数成以20后的数字 mov 0x4(%eax),%eax //在以上面计算的结果为地址的地方后推4位取一个值 cmp $0x1,%eax //用上面的值于一比较 je 804926a <put_mines+0x214> //相同就转移。
分析得出 :
作者用了一个长度为20个字节的数据机构来表示地雷的相关信息,而从第五个字节开始的四个字节数据表示的是一个地雷的有无如果为一有雷,为其他的为空。而这个数据结构的基地址就保存在0x804b2c4处。(呵呵,额外的信息,我个人感觉一个雷的数据结构会有五个数据,每个4字节。因为通篇反汇编文件都是eax,ecx在操作,也就是都是4个字节的处理。没有出现cx,ch,cl的运用....题外话。)
这样我们的反汇编分析到此就算是结束了...下面我们的工作就是利用神奇的ptrace函数来实现我们的外挂了.......
代码:
//Magic Ptrace #include<sys/ptrace.h> #include<stdio.h> #include<stdlib.h> #include<string.h> int main(int argc,char **argv) { int addr=0,pid,i,data[100]; pid=atoi(argv[1]); ptrace(PTRACE_ATTACH,pid); addr=ptrace(PTRACE_PEEKTEXT,pid,0x804b2c4); //以此地址读数据结构的基址... for(i=0;i<100;i++) data[i]=ptrace(PTRACE_PEEKTEXT,pid,addr+i*20+4); ptrace(PTRACE_DETACH,pid); for(i=0;i<100;i++) { if(!(i%10)) printf("\n"); printf("%d",data[i]); } printf("\n"); return 0; } //编译方法 就是最简单的 gcc -o crack.o crack.c //先执行mines的游戏(游戏名一定要是mines),再执行以下的命令行 //./crack.o `ps -A|grep mines|awk '{print $1}'`
结论:
好多朋友的都在问不懂编程能不能做逆向,实际上不是不能,只是要想有很好的提高和进步懂得编程思想是必不可少的。
本文很多地方都是在猜想作者的编程思路才分析出来的......大家共勉....