申请会员ID: freeGod【未报到,账号已删除】
1、申 请 I D:FreeGod2、个人邮箱:netfreegod3@126.com
3、原创技术文章: qq反汇编日志
标 题: 【原创】qq反汇编日志1
作 者: freeGod
时 间: 2006-06-15,18:20:36
链 接: http://bbs.pediy.com/showthread.php?t=27458
2006年6月15日 9:30
oo,前两天的反汇编记录下来的东西都丢了(昨天重做系统时,忘了),不过还好,丢的东西大部分都是我的曲折错误分析
现在从新开始:(为写远程暴力破解qq密码程序而反汇编qq)
反汇编工具:OllyICE
现在开始:
用OllyICE加载qq.exe,qq登录对话框出现,随便输入密码:123,运行,一个错误对话框出现,
错误
输入密码与上次成功登录得密码不一致,
是否到服务器验证?
好,打开OllyICE的模块窗口,然后找到user32模块,打开右键菜单选中查看名称,OllyICE的名称窗口出现了,这里的函数都是
User32模块中的,好,找到MessageBoxA,打开右键菜单选中反汇编窗口中跟随,这样就到了MessageBoxA函数的入口点,按f2键设下
端点,设好后点刚才qq跳出来的错误对话框上的否,qq用户登录又出现了,再输入123
OllyICE在我们刚才设置的MessageBoxA函数的入口点停了下来,察看堆栈窗口
0012FC2C 60B5C8E7/CALL 到 MessageBoxA 来自 MFC42.60B5C8E1
说明调用是MFC42库中的60b5c8e1处的指令的前一条指令调用了MessageBoxA,在CALL 到 MessageBoxA 来自 MFC42.60B5C8E1上
右键,打开右键菜单,选中反汇编窗口跟随,就到mfc42地址空间的60b5c8e7指令位置(不同的电脑,可能值不一样),上一条指令
就是调用MessageBoxA函数的,如下所示
60B5C8DC|.FF7424 10 push dword ptr ; |Text
60B5C8E0|.51 push ecx ; |hOwner
60B5C8E1|.FF15 D0B5B960 call [<&USER32.MessageBoxA>] ; \MessageBoxA
60B5C8E7|.5E pop esi
60B5C8E8|.C2 0C00 retn 0C
在 60b5c8e7 pop esi上设置端点,然后点运行,刚才的那个错误对话框又出现了,点否,好,现在程序停在了我们刚才设置端点的位
置605c8e7处,现在在MFC42地址空间中,不管它,我们想到的位置是qq空间,按两下f8键,到了 00415c35 cmp eax,6 指令处,看一
下OllyICE的标题栏 OllyICE - QQ.exe -
好了这就是我们的目的地。
反汇编就从这里开始,第一个分析的函数就是:包含 指令地址00415c35 的函数
第一步:找出 包含指令地址 00415c35 的 函数入口点
向上滚动反汇编窗口,找到00415b55 地址
00415B52\.C2 0400 retn 4
00415B55/$B8 5CD24C00 mov eax, 004CD25C
00415B5A|.E8 41A10500 call 0046FCA0
00415B5F|.83EC 48 sub esp, 48
OllyICE 分析出这个是函数的入口点,因为上面紧跟的是retn指令,不过一般的函数入口处:应该是
pushebp
movebp,esp
才对,如果是罗函数的话,经过优化编译的话就不是这个样子了,我们先在反汇编的是qq,qq的软件工程师水平应该是可以
的,有可能经过特殊处理,
004CD25C=004CD25C
eax=0012FCBC
本地调用来自 00414FE8, 00416FEE
这个交叉引用说明,的确是函数的入口点
这样函数入口点就确定了:004b5b55
第二步:确定函数结束地址,按OllyICE 的提示 结束地址应为:00415c9b retn 14,一个函数有可能有多个出口
我们来做进一步的鉴定,看看从004b5b55 到 00415c9b 之间的指令有无交叉引用到 00415c9b 以后的指令
答:没有,因此 00415c9b 即为函数的结束地址,至此我们确定了函数的入口点和结束地址
004b5b55--00415c9b
现在我们开始还原 函数 qq004b55 的源代码
第三步:确定参数个数和参数类型
找到调用 004b5b55 函数 指令 :00414fe8 ------------------------------------
|
00414FD6|.C645 FC 05 mov byte ptr , 5 |
00414FDA|.E8 A1A60500 call <jmp.&MFC42.#535_CString::CString> |
00414FDF|.FF75 EC push dword ptr |
00414FE2|.8BCB mov ecx, ebx |
00414FE4|.C645 FC 05 mov byte ptr , 5 |
00414FE8|.E8 680B0000 call 00415B55 ---------------------------------
00414FED|.FFD6 call esi
00414FE2|.8BCB mov ecx, ebx --- ecx 应该是个寄存器参数,要不这条指令就是个垃圾指令
函数004b5b55 可能有一个寄存器参数,说可能,是因为编译器生成的垃圾指令到处可见,要对ecx进一步鉴定,要
分析004b5b55 函数的代码
00415B55/$B8 5CD24C00 mov eax, 004CD25C
00415B5A|.E8 41A10500 call 0046FCA0
00415B5F|.83EC 48 sub esp, 48
00415B62|.53 push ebx
00415B63|.56 push esi
00415B64|.33DB xor ebx, ebx
00415B66|.895D FC mov , ebx
00415B69|.895D F0 mov , ebx
00415B6C|.8B81 84000000 mov eax,
在函数的开始处,调用了一个函数 0046fca0,察看一下它的代码,看看和ecx有染没有
0046FCA0/$6A FF push -1
0046FCA2|.50 push eax
0046FCA3|.64:A1 0000000>mov eax, fs:
0046FCA9|.50 push eax
0046FCAA|.8B4424 0C mov eax,
0046FCAE|.64:8925 00000>mov fs:, esp
0046FCB5|.896C24 0C mov , ebp
0046FCB9|.8D6C24 0C lea ebp,
0046FCBD|.50 push eax
0046FCBE\.C3 retn
哈哈,这个函数挺简练的,和ecx无关,这就好,再看看00415b6c地址 以上的指令都与ecx无关,而在00415b6c处引用了
ecx,因此断定ecx就是一个寄存器参数,不错,good
下面来看一下004b5b55 函数 有多少个堆栈参数
从函数结束地址 00415C9B\.C2 1400 retn 14
可知 堆栈参数个数为 14h / 4 = 5
到此我们确定了参数的个数:一个寄存器参数 + 5 个堆栈参数 = 6(说明函数采用的是fastcall调用方式)
给他们编号分别为:arg1,arg2,arg3,arg4,arg5,arg6
下面我们来确定参数类型
在指令中识别参数
函数004b5b55 每有标准的函数头 即 push ebp ; mov ebp,esp,如果是采用优化编译的话,参数应该用esp寄存器来寻址
可在函数过程中只在分配局部变量时,用了一次esp
00415B5F|.83EC 48 sub esp, 48
其他的地方都没有,令人奇怪的是到处都是用ebp寄存器寻址的,对了,函数入口点,调用了一个函数:0046fca0
看看它都实现了什么功能
0046FCA0/$6A FF push -1
执行指令后堆栈数据
相对esp的地址 数据
esp -1
esp+4 ret addr
0046FCA2|.50 push eax
执行指令后堆栈数据
相对esp的地址 数据
esp eax (通过寄存器eax传递过来的参数进栈)
esp+4 -1
esp+8 ret addr
0046FCA3|.64:A1 0000000>mov eax, fs: ;eax 指向 seh (结构化异常处理)
0046FCA9|.50 push eax
执行指令后堆栈数据
相对esp的地址 数据
esp eax (seh 指针)
esp+4 eax (通过寄存器eax传递过来的参数进栈)
esp+8 -1
esp+c ret addr
0046FCAA|.8B4424 0C mov eax, ;把ret addr 传递给eax
执行指令后堆栈数据
相对esp的地址 数据
esp eax (seh 指针)
esp+4 eax (通过寄存器eax传递过来的参数进栈)
esp+8 -1
esp+c ret addr
0046FCAE|.64:8925 00000>mov fs:, esp ;此时esp指向一个 EXCEPTION_REGISTRATION 结构
;表明同过寄存器eax传递给函数的是异常回调函数地址
;-1 则是seh 的附加数据
执行指令后堆栈数据
相对esp的地址 数据
esp eax (seh 指针)<-------------------------------fs:
esp+4 eax (通过寄存器eax传递过来的参数进栈)
esp+8 -1
esp+c ret addr
0046FCB5|.896C24 0C mov , ebp;保存ebp 到 原来 ret addr 所占堆栈位置
执行指令后堆栈数据
相对esp的地址 数据
esp eax (seh 指针)<-------------------------------fs:
esp+4 eax (通过寄存器eax传递过来的参数进栈)
esp+8 -1
esp+c ebp----- 注意发生变化了
0046FCB9|.8D6C24 0C lea ebp, ;ebp指向 保存ebp的位置(也即原来 ret addr 的位置)
执行指令后堆栈数据
相对esp的地址 数据
esp eax (seh 指针)<-------------------------------fs:
esp+4 eax (通过寄存器eax传递过来的参数进栈)
esp+8 -1
esp+c ebp----- 注意发生变化了<------------------------ ebp
0046FCBD|.50 push eax
执行指令后堆栈数据
相对ebp的地址 相对esp的地址 数据
ebp-10 esp eax(函数的返回地址)
ebp-c esp+4 eax (seh 指针)<-------------------------------fs:
ebp-8 esp+8 eax (通过寄存器eax传递过来的参数进栈)
ebp-4 esp+c -1
ebp esp+10 ebp----- 注意发生变化了<------------------------ ebp
0046FCBE\.C3 retn
执行指令后堆栈数据
相对ebp的地址 相对esp的地址 数据
ebp-c esp eax (seh 指针)<-------------------------------fs:
ebp-8 esp+4 eax (通过寄存器eax传递过来的参数进栈)
ebp-4 esp+8 -1
ebp esp+c ebp----- 注意发生变化了<------------------------ ebp
因为 函数0046fca0没有堆栈参数,所以 ebp+4 指向的是它的父函数即 004b5b55 结束时要返回的地址
相对ebp的地址 相对esp的地址 数据
ebp-c esp eax (seh 指针)<-------------------------------fs:
ebp-8 esp+4 eax (通过寄存器eax传递过来的参数进栈)
ebp-4 esp+8 -1
ebp esp+c ebp----- 注意发生变化了<------------------------ ebp
ebp +4 esp+10 004b5b55函数 结束时要返回的地址
综上所述:0046fca0 实现的功能为:《1》注册异常回调函数
《2》实现了和 pushebp
movebp,esp
查不多的功能,调用0046fca0函数的函数的第一个堆栈参数地址为 ebp +8
这和push ebp ;move ebp,esp 是一样的,但是局部变量的寻址就不一样了
调用0046fca0 函数的函数局部变量是从ebp-d 开始的,而不是从ebp-4开始的
搞定……^_^
现在我们就可以很轻松的识别出参数了,开始吧
识别参数类型
首先我用32位汇编语言来实现00415b55,我给他起个名字叫 _lastStep 吧,我把寄存器传参也改成堆栈方式
_LastStepproc_arg1,_arg2,_arg3,_arg4,_arg5,_arg6
moveax,004cd25c
call0046fca0
subesp,48h
pushebx
pushesi
xorebx,ebx
mov,ebx; 是seh附加数据的地址,原来值为-1,现在要把它置零了
mov@dwVar1,ebx
movecx,_arg1
moveax,;可知_arg1 是一个指针
leaedx,@dwVar1
pushedx
push004e7460
movecx,
pusheax
movbyte ptr,1; 是seh附加数据的地址
call ;表明_arg1 是一个函数指针的指针的指针
testeax,eax
jnzlable1
moveax,@dwVar1
leaedx,@dwVar2
pushedx
push004e8940 ;ascii "ewh.db"
movecx,
pusheax
call
testeax,eax
jelabel2
lable1:
moveax,_arg4 ;可知_arg4 是一个int*
movdword ptr,2
jmplable3
lable2:
moveax,_arg3
pushedi
movedx,@dwVar1
push1
movecx,
popesi
movedi,
pushesi
pusheax
pushecx
pushebx
pushdword ptr _arg2
pushedx
call
testeax,eax
popedi
jelable4
cmp_arg6,esi
jelable5
moveax,_arg4
mov,ebx;可知_arg4是个指针
jmplable3
lable5:
leaecx,_arg6
callCString::CString
leaecx,_arg2
movbyte ptr ,2
callCString::CString
movesi,BasicCtrDll.BasicLoadStr
leaeax,_arg6
push281
pusheax
movbyte prt,3
callesi
leaeax,_arg2
push28d
pusheax
callesi
addesp,10
leaecx,;ebp-54 指向一个结构
callCWNd::CWnd
push114
leaecx,
pushdword ptr _arg2
movbyte prt,4
pushdword ptr _arg6
callCWnd::MessageBoxA
cmpeax,6
moveax,_arg4
jnzLable6
movdword prt,2
jmplable7
lable6:
mov,ebx
lable7:
leaecx,
movbyte ptr,3
callCWnd::~Cwnd
leaecx,_arg2
movbyte ptr,2
callCString::~CString
leaecx,_arg6
movbyte ptr,1
callCString::~Cstring
jmplable3
lable4:
moveax,_arg4
mov,esi
lable3:
moveax,@dwVar1
mov,bl
cmpeax,ebx
jelable8
movecx,
pusheax
call
lable8:
ordwword ptr,0ffffffffh
leaecx,_arg3
callCString::~CString
movecx,; pre seh handler 指针
popesi
popebx
movfs:,ecx
leave
retn14
_LastSetpenp
今天就到这里,明天继续
2006-6-15 13:20
请在看雪论坛给hmilywen发一条短消息我确认下是否是本人。 已经发送了短消息 ID:FreeGod
邮箱:netfreegod3@126.com
申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。 一周内在未报道,删除账号。
页:
[1]