分享
 
 
 

dll反汇编初步

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

在论坛里面看到一些人讨论dll的反汇编,这几天帮一个朋友分析一个dll,此dll非常简单,现在把我的分析过

程和大家分享一下,这里没有什么特别有效的方法,靠的就是耐心和经验,反复验证,直到调用成功。

有个dll2lib的工具,不知道是我不会使用还是怎么的,反正我是没有使用成功过,所以我只能靠自己

来分析了。

首先是使用的工具,ida/win32dasm/ollydbg

win32dasm分析的速度快一些,但是智能程度不如ida,ida这个2001开发工具亚军绝对不是浪得虚名的

,它的智能程度非常高,可是识别出常用的函数,这两个都是静态反汇编的工具,必须配以动态分析的工具,

毕竟你很难一下子就分析对(至少我是这样),当然你可以使用s-ice或者trw,但是这些工具都有限制,trw不支

持2000,s-ice一旦装载只能reboot才能取消装载,还有其工作在ring0,所以你只能对者黑乎乎的屏幕,很痛

苦,这里选用的ollydbg是最新版本,支持dll的跟踪。

下面列出win32dasm反汇编的结果:

Exported fn(): GetUserNumber - Ord:0004h

:0040C1B0 55 push ebp

:0040C1B1 8BEC mov ebp, esp

:0040C1B3 53 push ebx

:0040C1B4 56 push esi

:0040C1B5 57 push edi

:0040C1B6 8B5D08 mov ebx, dword ptr [ebp+08]

:0040C1B9 33F6 xor esi, esi

:0040C1BB 8BC3 mov eax, ebx

:0040C1BD E846A5FFFF call 00406708

:0040C1C2 6685C0 test ax, ax

:0040C1C5 7212 jb 0040C1D9

:0040C1C7 40 inc eax

:0040C1C8 33D2 xor edx, edx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C1D7(C)

|

:0040C1CA 0FB7CA movzx ecx, dx

:0040C1CD 0FB60C0B movzx ecx, byte ptr [ebx+ecx]

:0040C1D1 03F1 add esi, ecx

:0040C1D3 42 inc edx

:0040C1D4 66FFC8 dec ax

:0040C1D7 75F1 jne 0040C1CA

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C1C5(C)

|

:0040C1D9 8B450C mov eax, dword ptr [ebp+0C]

:0040C1DC 8A4012 mov al, byte ptr [eax+12]

:0040C1DF 3C61 cmp al, 61

:0040C1E1 720B jb 0040C1EE

:0040C1E3 25FF000000 and eax, 000000FF

:0040C1E8 6683E861 sub ax, 0061

:0040C1EC EB09 jmp 0040C1F7

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C1E1(C)

|

:0040C1EE 25FF000000 and eax, 000000FF

:0040C1F3 6683E841 sub ax, 0041

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C1EC(U)

|

:0040C1F7 8B550C mov edx, dword ptr [ebp+0C]

:0040C1FA 8A5213 mov dl, byte ptr [edx+13]

:0040C1FD 80FA61 cmp dl, 61

:0040C200 720C jb 0040C20E

:0040C202 81E2FF000000 and edx, 000000FF

:0040C208 6683EA61 sub dx, 0061

:0040C20C EB0A jmp 0040C218

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C200(C)

|

:0040C20E 81E2FF000000 and edx, 000000FF

:0040C214 6683EA41 sub dx, 0041

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C20C(U)

|

:0040C218 0FB7C0 movzx eax, ax

:0040C21B 6BF81A imul edi, eax, 0000001A

:0040C21E 0FB7C2 movzx eax, dx

:0040C221 03F8 add edi, eax

:0040C223 81F74D010000 xor edi, 0000014D

:0040C229 83F701 xor edi, 00000001

:0040C22C 8BC3 mov eax, ebx

:0040C22E E8D5A4FFFF call 00406708

:0040C233 2BF8 sub edi, eax

:0040C235 8BC6 mov eax, esi

:0040C237 B91A000000 mov ecx, 0000001A

:0040C23C 99 cdq

:0040C23D F7F9 idiv ecx

:0040C23F 2BFA sub edi, edx

:0040C241 8BC7 mov eax, edi

:0040C243 5F pop edi

:0040C244 5E pop esi

:0040C245 5B pop ebx

:0040C246 5D pop ebp

:0040C247 C20800 ret 0008

通过ret 008我们可以知道这个函数需要两个参数,通过mov eax, esi,我们可以知道这个函数有反回

值(这是因为在高级语言里面一般通过eax设置函数返回值)具体返回什么类型现在还没办法知道,但是不管这么

多,我们假设此函数是这样的:

int GetUserNumber(int a1,int a2)

我们会在后续分析后,慢慢修正他,现在我们开始一点点分析。

:0040C1B0 55 push ebp

:0040C1B1 8BEC mov ebp, esp

:0040C1B3 53 push ebx

:0040C1B4 56 push esi

:0040C1B5 57 push edi

这个是function prolog,建立堆栈和寄存器的保存,没什么可多说的。

:0040C1B6 8B5D08 mov ebx, dword ptr [ebp+08]

:0040C1B9 33F6 xor esi, esi

:0040C1BB 8BC3 mov eax, ebx

:0040C1BD E846A5FFFF call 00406708

这里你需要知道函数调用过程的参数传递,可以到asm.yeah.net看看罗云彬那篇很好的关于参数传递和堆栈修

复的文章,这里简单说一下,调用函数的时候如果通过堆栈来传递参数的话,那么对于我们讨论的函数可能是

这样的:

push a2

push a1

call GetUserNumber

此时堆栈看起来是这样的

-----a2

-----a1

esp-> -----returnaddress

这时候进入函数内部push ebp后

esp+c -----a2

esp+8 -----a1

esp+4 -----returnaddress

esp-> -----ebp

mov ebp,esp

此时要寻址a1可以通过ebp+8

:0040C1B6 8B5D08 mov ebx, dword ptr [ebp+08]; ebx保存第一个参数

:0040C1B9 33F6 xor esi, esi

:0040C1BB 8BC3 mov eax, ebx

:0040C1BD E846A5FFFF call 00406708

这个很简单esi清零,把第一个参数传递给eax,然后调用00406708

所以我们接下来就是要到00406708里面去看看

:00406708 89FA mov edx, edi

:0040670A 89C7 mov edi, eax

:0040670C B9FFFFFFFF mov ecx, FFFFFFFF

:00406711 30C0 xor al, al

:00406713 F2 repnz

:00406714 AE scasb

:00406715 B8FEFFFFFF mov eax, FFFFFFFE

:0040671A 29C8 sub eax, ecx

:0040671C 89D7 mov edi, edx

:0040671E C3 ret

这个是很典型的求字符串长度的代码

:00406708 89FA mov edx, edi ;保存edi

:0040670A 89C7 mov edi, eax ;eax是我们调用前的a1

:0040670C B9FFFFFFFF mov ecx, FFFFFFFF ecx设置成最大32数

:00406711 30C0 xor al, al ;al清零

我们知道汇编指令的字符串操作一般通过esi和edi,上面的过程在注释里给出解释

:00406713 F2 repnz

:00406714 AE scasb ;判断字符串是否结束

:00406715 B8FEFFFFFF mov eax, FFFFFFFE

:0040671A 29C8 sub eax, ecx ;eax保存了字符串长度

:0040671C 89D7 mov edi, edx ;恢复edi

:0040671E C3 ret

上面分析我们知道参数a1是一个字符串,现在把我们的函数修正如下

int GetUserNumber(char * a1,int a2)

继续我们的分析:

:0040C1C2 6685C0 test ax, ax ;长度是否为零

:0040C1C5 7212 jb 0040C1D9 ;为零则跳转

:0040C1C7 40 inc eax ;eax加一

:0040C1C8 33D2 xor edx, edx ;edx清零

我们用c语言写出等价程序如下:

int GetUserNumber(char * strUserName,test * pt)

{

esi = 0;

int len = strlen(strUserName);

if(len <= 0)

goto _SKIP_USERNAME;

_SKIP_USERNAME:

}

继续分析并且进一步修正我们的代码

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C1D7(C)

|

:0040C1CA 0FB7CA movzx ecx, dx ;ecx置零

:0040C1CD 0FB60C0B movzx ecx, byte ptr [ebx+ecx] ;ebx保存第一个参数

:0040C1D1 03F1 add esi, ecx ;取出字符串的第ecx位

:0040C1D3 42 inc edx ;edx加一

:0040C1D4 66FFC8 dec ax ;ax字符串长度减一

:0040C1D7 75F1 jne 0040C1CA ;字符串未处理完则继续

上面是典型的基址加变址寻址模式,很简单,等价的c代码如下:

int GetUserNumber(char * strUserName,test * pt)

{

esi = 0;

int len = strlen(strUserName);

if(len <= 0)

goto _SKIP_USERNAME;

for(int i = 0 ; i < len ; ++i)

{

esi += strUserName[i]; //计算用户名ASC和

}

_SKIP_USERNAME:

}

继续分析并且进一步修正我们的代码

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C1C5(C)

|

:0040C1D9 8B450C mov eax, dword ptr [ebp+0C] ;取第二个参数

:0040C1DC 8A4012 mov al, byte ptr [eax+12] ;移动0X12=18个字节

:0040C1DF 3C61 cmp al, 61 ;与0X61='a'比较

:0040C1E1 720B jb 0040C1EE ;小于则跳

:0040C1E3 25FF000000 and eax, 000000FF ;保留eax的低8位

:0040C1E8 6683E861 sub ax, 0061 ;计算与'a'的差距

:0040C1EC EB09 jmp 0040C1F7 ;跳到0040C1F7

能看出在第一个参数表示的字符串长度是0的时候会直接跳到这里。

这里的问题是我们如何知道第二个参数的类型呢?

答案是没办法知道,因为就现在这些信息,我们没有办法知道第二个参数是什么类型,但是一定是一块内存区

域,因为mov al, byte ptr [eax+12]这段代码告诉我们的,现在我们来模拟出来这段区域

我们定义一个结构来模拟,事实上我们在写程序的时候,如果调用函数时候参数类型不匹配,会得到编译错误

,其实这个错误是编译器给出来的,他与我们能否成功调用函数无关,因为如果类型真的不匹配,运行时会出

错,所以调用dll的时候我们的参数类型未必一定要和实际dll原代码实现的是一模一样的,但是一定要兼容。

所以我用结构来模拟,并不会破坏我们讨论的问题的一般性。

定义如下结构:

struct test

{

char c18_unused[18];

char c19;

};

现在重新修正我们的函数

int GetUserNumber(char * strUserName,test * pt)

{

int esi;

char al;

esi = 0;

int len = strlen(strUserName);

if(len <= 0)

goto _SKIP_USERNAME;

for(int i = 0 ; i < len ; ++i)

{

esi += strUserName[i]; //计算用户名ASC和

}

_SKIP_USERNAME:

al = pt->c19_IsNumber;

if(al < 'a') //判断字符大小写

goto IsLower;

}

继续分析

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C1E1(C)

|

:0040C1EE 25FF000000 and eax, 000000FF ;cmp al, 61后会跳到这里,eax保留低8位

:0040C1F3 6683E841 sub ax, 0041 ;0x41='A',计算与'A'差距

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C1EC(U)

|

:0040C1F7 8B550C mov edx, dword ptr [ebp+0C] ;edx保存第二个参数

:0040C1FA 8A5213 mov dl, byte ptr [edx+13] ;取0x13=19位

:0040C1FD 80FA61 cmp dl, 61

:0040C200 720C jb 0040C20E

:0040C202 81E2FF000000 and edx, 000000FF

:0040C208 6683EA61 sub dx, 0061

:0040C20C EB0A jmp 0040C218

上面这段与上面的代码几乎一样,不做分析。值得一提的是我们需要修正我们前面定义的结构,修正后:

struct test

{

char c18_unused[18];

char c19;

char c20

};

等价c代码

int esi;

char al;

char dl;

int edx;

int edi;

int eax;

int ecx;

esi = 0;

int len = strlen(strUserName);

if(len <= 0)

goto _SKIP_USERNAME;

for(int i = 0 ; i < len ; ++i)

{

esi += strUserName[i]; //计算用户名ASC和

}

_SKIP_USERNAME:

al = pt->c19_IsNumber;

if(al < 'a') //判断字符大小写

goto IsNumber1;

al -= 'a';

goto _CONTINUE1;

IsNumber1:

al -= 'A';

_CONTINUE1:

dl = pt->c20_IsNumber;

if(dl < 'a') //判断字符大小写

goto IsNumber2;

dl -= 'a';

goto _CONTINUE2;

IsNumber2:

dl -= 'A';

}

我们的目标快要到达了,最后的一段代码

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040C20C(U)

|

:0040C218 0FB7C0 movzx eax, ax

:0040C21B 6BF81A imul edi, eax, 0000001A

:0040C21E 0FB7C2 movzx eax, dx

:0040C221 03F8 add edi, eax

:0040C223 81F74D010000 xor edi, 0000014D

:0040C229 83F701 xor edi, 00000001

:0040C22C 8BC3 mov eax, ebx ;第一个参数

:0040C22E E8D5A4FFFF call 00406708 ;和前面分析一样求长度

:0040C233 2BF8 sub edi, eax ;减去长度值

:0040C235 8BC6 mov eax, esi ;esi是第一个参数asc码和

:0040C237 B91A000000 mov ecx, 0000001A ;ecx=0x1a=26

:0040C23C 99 cdq ;eax扩展成edx:eax

:0040C23D F7F9 idiv ecx ;除以ecx=26

:0040C23F 2BFA sub edi, edx ;减去余数

:0040C241 8BC7 mov eax, edi ;传给eax

:0040C243 5F pop edi

:0040C244 5E pop esi

:0040C245 5B pop ebx

:0040C246 5D pop ebp

:0040C247 C20800 ret 0008

这段代码也很简单,到这里我们得到近似的c源代码,这里对于cdq指令完成的功能我没有实现,但是这对问题

没有影响:

int GetUserNumber(char * strUserName,test * pt)

{

int esi;

char al;

char dl;

int edx;

int edi;

int eax;

int ecx;

esi = 0;

int len = strlen(strUserName);

if(len <= 0)

goto _SKIP_USERNAME;

for(int i = 0 ; i < len ; ++i)

{

esi += strUserName[i]; //计算用户名ASC和

}

_SKIP_USERNAME:

al = pt->c19_IsNumber;

if(al < 'a') //判断字符大小写

goto IsNumber1;

al -= 'a';

goto _CONTINUE1;

IsNumber1:

al -= 'A';

_CONTINUE1:

dl = pt->c20_IsNumber;

if(dl < 'a') //判断字符大小写

goto IsNumber2;

dl -= 'a';

goto _CONTINUE2;

IsNumber2:

dl -= 'A';

_CONTINUE2:

edi = al*0x1a;//26

eax = dl;

edi += eax;

edi^=0x14d;

edi^=0x1;

edi -= len;

eax = esi;

ecx = 0x1a; //26

//edx = eax的符号位扩展

edx = eax%ecx;

eax/=ecx;

edi -= edx;

eax = edi;

return eax;

}

到这里整个分析就结束了,我要说的是这里分析的函数比较简单,不具有一般性,涉及到更复杂的函数,比如

虚拟函数、类的分析,这里我的分析没有什么技术型可言,只是就一些简单的dll函数的反汇编,给出我的一点

经验,对您有帮助我感到很荣幸,对你没帮助浪费了您的时间我感到抱歉,希望您别骂我就好.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有