首页
论坛
课程
招聘
[注意]逆向基础知识学习
2007-9-1 10:45 44898

[注意]逆向基础知识学习

2007-9-1 10:45
44898
标 题: 【注意】逆向基础知识学习
作 者: kanxue
时 间: 2007-09-01,10:45
链 接: http://bbs.pediy.com/showthread.php?t=50879


声明:这份是看雪论坛学习交流小组内部交流的资料, 现在放出来

一直建议学习解密的朋友,一定要掌握好汇编和Win32编程(Charles Petzold著的《Windows程序设计》),磨刀不误砍柴功。

代码的逆向分析基础也没过多的技巧,掌握一些基本原理后,自己写些小程序,然后再看反汇编代码理解意思,进步会很快的。

有一些内容,在新兵论坛的置顶帖里己有,如: 【资料】解密基础知识入门

第1部分 函数

1.1 函数参数
传递参数有如下情况:
①利用堆栈传递参数;
②利用寄存器传递参数。
③通过全局变量进行隐含参数的传递
函数调用中需要解决几个问题:
1. 当参数个数多于一个时,按照什么顺序把参数压入堆栈。
2. 函数调用后,由谁来把堆栈恢复。
在高级语言中,通过调用约定来说明这两个问题。
常见的调用约定有:__cdecl调用约定,__PASCAL调用约定,__stdcall调用约定,thiscall调用约定。
假设调用函数是:test1(Par1,Par2, Par3):


1.1.1 __stdcall调用约定
按__stdcall约定调用函数test2(Par1, Par2)
push par2 ; 参数2
push par1 ; 参数1
call test2;
{
push ebp ; 保护现场原先的EBP指针
mov ebp, esp ; 设置新的EBP指针,指向栈顶
mov eax, [ebp+0C] ; 调用参数2
mov ebx, [ebp+08] ; 调用参数1
sub esp, 8 ; 创建局部变量,在堆栈中分配些空间

add esp, 8 ; 释放局部变量占用的堆栈
pop ebp ; 恢复现场的ebp指针
ret 8 ; 返回(相当于ret; add esp,8)
}
用OllyDBG打开实例 add.rar ,对照下图理解堆栈的参数是如何传递的。



1.1.2 this指针
在C++程序中,对象的每个函数隐含地接受this参数——指向对象实例的指针,函数调用是通过对象实例进行的。只要使用this指针,就能确定被调用的函数究竟属于哪个对象实例。由于虚函数的地址是在调用即将进行之前加以确定的,因此如果不存在this指针,重载函数之间的层次结构将不可能做到的。
一般情况下,每个编译器都有自己的特别之处。下面是不同编译器中传递this指针的简表:


1.2 函数返回值

函数的返回值通常是由return操作符返回的一个值。从汇编角度来看,主要有如下形式:

1)通过寄存器返回函数值;
2)通过参数按引用方式返回函数值;
3)通过全局变量返回函数值;
4)通过处理器标志返回函数值;

一般情况下,由retrun操作符返回的值放在EAX寄存器之中,如果结果超过这个寄存器的位容量,那么该结果的高32位会加载到EDX寄存器中。
如果返回一个含有几百个字节的结构或者一个近似大小的对象,编译器会在不告诉程序的情况下,给函数传递一个隐式参数,这个指针指向保存的返回结果。
1.3 局部变量

在子程序内部说明的变量称为局部变量,局部变量的作用域是其所在的子程序。从汇编角度来看,局部变量就是一个临时堆栈缓存,用完释放。
例如这个实例:附件:local.zip

其反汇编代码如下(红体字为局部变量):

00401000 >/$ 6A 04 push 4 ; /Arg2 = 00000004
00401002 |. 6A 03 push 3 ; |Arg1 = 00000003
00401004 |. E8 16000000 call 0040101F ; \Add.0040101F
00401009 |. 8BD8 mov ebx, eax
0040100B |. 6A 00 push 0 ; /ExitCode = 0
0040100D \. FF15 00204000 call [<&KERNEL32.ExitProcess>] ; \ExitProcess

0040101F /$ 55 push ebp ; 保护现场原先的EBP指针
00401020 |. 8BEC mov ebp, esp ; 设置新的EBP指针,指向栈顶
00401022 |. 83EC 04 sub esp, 4 ; 分配局部变量所有空间
00401025 |. 8B45 0C mov eax, [ebp+C] ; 调用参数2
00401028 |. 8B5D 08 mov ebx, [ebp+8] ; 调用参数1
0040102B |. 895D FC mov [ebp-4] , ebx ; 参数1放局部变量里
0040102E |. 0345 FC add eax,[ebp-4] ; 参数2与局部变量相加
00401031 |. 83C4 04 add esp, 4 ; 释放局部变量所有空间
00401034 |. 5D pop ebp ; 恢复现场的ebp指针
00401035 \. C2 0800 retn 8

安卓应用层抓包通杀脚本发布!《高研班》2021年3月班开始招生!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (59)
雪    币: 3144
活跃值: 活跃值 (2414)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2007-9-1 10:51
2
0
第2部分 控制语句

2.1 IF-THEN-ELSE语句

语句IF-THEN-编译后,其汇编代码形式一般如下:
cmp a,b
jz xxxx

各类条件跳转指令形式,各位一定要搞清楚,破解时经常用到。
如不清楚,可以看看这资料:http://www.pediy.com/tutorial/chap2/Chap2-3.htm

2.2  SWITCH-CASE语句

《黑客反汇编》这方面内容比较仔细,到时请哪位摘录些过来
雪    币: 3144
活跃值: 活跃值 (2414)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2007-9-1 10:52
3
0
第3部分 循环语句

留位
雪    币: 3144
活跃值: 活跃值 (2414)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2007-9-1 10:54
4
0
第4部分 全局变量

全局变量作用于整个程序,一直是存在的,它放在全局变量的内存区;而局部变量则是存在于函数的堆栈区,当函数调用结束后便消失。

这个比较好识别,如:
mov eax, dword ptr [403000]:直接调用全局变量,共中0x403000是全局变量的地址
雪    币: 3144
活跃值: 活跃值 (2414)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2007-9-1 10:57
5
0
第5部分 数据运算符

5.1 加法

加法运算符一般编译成ADD指令,编译优化时,都比较喜欢用LEA指令来代替ADD指令。LEA指令允许用户在一个时钟内完成d=a+b+c计算,会编译成LEA c,[a+b+c]指令。这个很常见,大家一定要注意。

5.2 减法

减法比较简单,都是SUB指令,好识别

5.3 乘法
(摘自《黑客反汇编》)









5.4 除法
上传的附件:
  • lea.gif (72.30kb,7306次下载)
  • 2.gif (104.62kb,7261次下载)
  • 3.gif (112.67kb,7231次下载)
  • 4.gif (29.06kb,7152次下载)
  • 5.gif (113.34kb,7203次下载)
雪    币: 3144
活跃值: 活跃值 (2414)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2007-9-1 11:01
6
0
第2部分 启动函数

在编写Win32应用程序时,都必须在源码里实现一个WinMain函数。但Windows程序执行并不是从WinMain函数开始的,首先被执行的是启动函数相关代码,这段代码是编译器生成的。启动代码完成初始化进程,再调用WinMain。标准编译器通常包含启动代码在内的库文件源码,例如Visual C++中,启动代码存放在CRT\SRC\crt0.c文件中。
所有的C/C++运行时启动函数的作用基本都是相同的:检索指向新进程的命令行指针,检索指向新进程的环境变量指针,全局变量初始化,内存堆栈初始化等。当所有的初始化操作完毕后,启动函数就调用应用程序的进入点函数。
调用WinMain如下所示:
GetStartupInfo (&StartupInfo);
Int nMainRetVal = WinMain(GetModuleHandle(NULL),NULL,pszCommandLineAnsi,(StartupInfo.dwFlags&STARTF_USESHOWWINDOW)?StartupInfo.wShowWindow:SW__SHOWDEFAULT);
当进入点返回时,启动函数便调用C运行库期的exit函数,将返回值(nMainRetVal)传递给它,进行一些必要处理,最后调用系统函数ExitProcess退出。
其他一些编译器,如Delphi、BorLand C++开发包中都有相应的启动代码。
在绝大数情况下,我们对启动代码并不需要关心。 对于逆向分析人员来说,首要的任务是找到Winmain函数。

WinMain函数原型如下:
int WINAPI WinMain(
HINSTANCE hInstance, // 当前实例的句柄
HINSTANCE hPrevInstance, // 前一个实例的句柄
LPSTR lpCmdLine, // 命令行的指针
int nCmdShow // 窗口的显示状态
);
其中参数hInstance一般通过GetModuleHandleA函数进行获取的,这对识别WinMain函数有些帮助。另外,对WinMain的调用通常放在启动函数代码结尾部分,后面通常跟着诸如exit或XcptFilter之内的两、三个函数。例如下面这段代码:
.text:004010DC push eax ; nShowCmd
.text:004010DD push [ebp+lpCmdLine] ; lpCmdLine
.text:004010E0 push esi ; hPrevInstance
.text:004010E1 push esi ; lpModuleName
.text:004010E2 call ds:GetModuleHandleA
.text:004010E8 push eax ; hInstance
.text:004010E9 call WinMain(x,x,x,x)
.text:004010EE mov [ebp+var_60], eax
.text:004010F1 push eax ; int
.text:004010F2 call _exit
许多开发人员可以得到启动源代码的情况下对启动代码进行修改,这样,程序的执行可能不是从WinMain开始,而是从任何其他的函数开始。

读者可以用OllyDBG调试一下附件的实例(Visual C++ 6.0编译)。
上传的附件:
雪    币: 3144
活跃值: 活跃值 (2414)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2007-9-1 11:21
7
0
习题1:
己知:EDI指向某字符串
下面代码功能是什么:
mov ecx, FFFFFFFF
sub eax, eax        
repnz   
scasb  
not ecx
dec ecx
雪    币: 1470
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
bithaha 活跃值 5 2007-9-1 11:51
8
0
这个帖子的跟帖不要水,可以把学习中碰到的问题在下面跟帖说明。
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kongruojun 活跃值 2007-9-1 15:41
9
0
原来习题出自这里,经过近般小时的努力才搞明白。
mov ecx, FFFFFFFF    设置循环次数-1
sub eax, eax             设置搜索内容0
repnz                        
scasb                         一直重复搜索到EDI字符串末尾的0
not ecx                       得到搜索次数,也就是字符串的完整长度
dec ecx                       -1得到字符串不包含末尾0的长度
雪    币: 1470
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
bithaha 活跃值 5 2007-9-1 16:27
10
0
这几行代码在分析算法的时候碰到的概率是100%.
请小组成员跟踪一下本帖附件中的HelloMsg程序找到程序的开始位置,并和http://bbs.pediy.com/showthread.php?t=50888这个帖子中的“源码”中的程序比较一下,这两个程序都是用VC6.0写的,他们的启动函数并不相同,原因在于main函数和WinMain函数的原型不同。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tiz 活跃值 2007-9-1 21:02
11
0
不要把答案这么早些写出来嘛,也让我好好想想
雪    币: 208
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ncdfly 活跃值 2007-12-21 15:03
12
0
谁能把HelloMsg反汇编代码 逐行的解释一下阿??特别想知道整个流程。
雪    币: 212
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wping 活跃值 2007-12-22 20:16
13
0
00401020 >/$  55            push    ebp
00401021  |.  8BEC          mov     ebp, esp
00401023  |.  6A FF         push    -1
00401025  |.  68 A0404000   push    004040A0
0040102A  |.  68 541B4000   push    00401B54                         ;  SE 处理程序安装
0040102F  |.  64:A1 0000000>mov     eax, dword ptr fs:[0]
00401035  |.  50            push    eax
00401036  |.  64:8925 00000>mov     dword ptr fs:[0], esp
0040103D  |.  83EC 58       sub     esp, 58
00401040  |.  53            push    ebx
00401041  |.  56            push    esi
00401042  |.  57            push    edi
00401043  |.  8965 E8       mov     dword ptr [ebp-18], esp
00401046  |.  FF15 14404000 call    dword ptr [<&KERNEL32.GetVersion>;  kernel32.GetVersion
0040104C  |.  33D2          xor     edx, edx
0040104E  |.  8AD4          mov     dl, ah
00401050  |.  8915 D4544000 mov     dword ptr [4054D4], edx
00401056  |.  8BC8          mov     ecx, eax
00401058  |.  81E1 FF000000 and     ecx, 0FF
0040105E  |.  890D D0544000 mov     dword ptr [4054D0], ecx
00401064  |.  C1E1 08       shl     ecx, 8
00401067  |.  03CA          add     ecx, edx
00401069  |.  890D CC544000 mov     dword ptr [4054CC], ecx
0040106F  |.  C1E8 10       shr     eax, 10
00401072  |.  A3 C8544000   mov     dword ptr [4054C8], eax
00401077  |.  33F6          xor     esi, esi
00401079  |.  56            push    esi
0040107A  |.  E8 A1090000   call    00401A20
0040107F  |.  59            pop     ecx
00401080  |.  85C0          test    eax, eax
00401082  |.  75 08         jnz     short 0040108C
00401084  |.  6A 1C         push    1C
00401086  |.  E8 B0000000   call    0040113B
0040108B  |.  59            pop     ecx
0040108C  |>  8975 FC       mov     dword ptr [ebp-4], esi
0040108F  |.  E8 E1070000   call    00401875
00401094  |.  FF15 10404000 call    dword ptr [<&KERNEL32.GetCommand>; [GetCommandLineA
0040109A  |.  A3 D8594000   mov     dword ptr [4059D8], eax
0040109F  |.  E8 9F060000   call    00401743
004010A4  |.  A3 B0544000   mov     dword ptr [4054B0], eax
004010A9  |.  E8 48040000   call    004014F6
004010AE  |.  E8 8A030000   call    0040143D
004010B3  |.  E8 A7000000   call    0040115F
004010B8  |.  8975 D0       mov     dword ptr [ebp-30], esi
004010BB  |.  8D45 A4       lea     eax, dword ptr [ebp-5C]
004010BE  |.  50            push    eax                              ; /pStartupinfo
004010BF  |.  FF15 0C404000 call    dword ptr [<&KERNEL32.GetStartup>; \GetStartupInfoA
004010C5  |.  E8 1B030000   call    004013E5
004010CA  |.  8945 9C       mov     dword ptr [ebp-64], eax
004010CD  |.  F645 D0 01    test    byte ptr [ebp-30], 1
004010D1  |.  74 06         je      short 004010D9
004010D3  |.  0FB745 D4     movzx   eax, word ptr [ebp-2C]
004010D7  |.  EB 03         jmp     short 004010DC
004010D9  |>  6A 0A         push    0A
004010DB  |.  58            pop     eax
004010DC  |>  50            push    eax
004010DD  |.  FF75 9C       push    dword ptr [ebp-64]
004010E0  |.  56            push    esi
004010E1  |.  56            push    esi                              ; /pModule
004010E2  |.  FF15 08404000 call    dword ptr [<&KERNEL32.GetModuleH>; \GetModuleHandleA
004010E8  |.  50            push    eax
004010E9  |.  E8 12FFFFFF   call    00401000

其实程序的主体就是这个call    00401000  那么是否可以认定这之前的代码,几乎每个程序都是一样的(都用一个编译器)
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小小派Y 活跃值 2008-1-18 23:53
14
0
谢谢,努力学习吧,呵呵
雪    币: 271
活跃值: 活跃值 (31)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
theendone 活跃值 2008-1-31 05:58
15
0
呵呵,学习一下
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
guoqianyi 活跃值 2008-2-17 16:58
16
0
东西是很好,可惜看不懂。
雪    币: 205
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pushpop 活跃值 2008-2-18 17:11
17
0
各位菜菜鸟们(比我还菜的)注意一下这段代码开头¨se处理程序安装¨提示和push —1;
有位老鸟(好像是那个写“笑解api”的)就是用它得到模块地址的。
本人也是菜鸟不对的请更正。
雪    币: 212
活跃值: 活跃值 (10)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
安摧 活跃值 2 2008-2-18 19:27
18
0
大家都辛苦了。
过节刚回来
哈哈
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
vacanoo 活跃值 2008-2-19 00:06
19
0
很不错的文章,我要好好学习下
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ejxin 活跃值 2008-2-25 10:29
20
0
呵呵 有很大的帮助 刚刚就用到了
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhaoxili 活跃值 2008-2-28 23:33
21
0
恩 要好好学习了啊
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
peilan 活跃值 2008-2-29 02:24
22
0
好好学习,天天向上!
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
znfwhy 活跃值 2008-3-21 14:15
23
0
假定EDI指向以末\0结尾字符串,则:
……
repnz scasb;扫描字符串,找到其结尾
……
not ecx
dec ecx;将字符串长度置ecx
整段代码类似C中的strlen函数功能

这是我的理解,不当之处还望各位指正,谢谢!
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
singyys 活跃值 2008-3-23 21:35
24
0
学习了!谢谢.
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fairgh 活跃值 2008-3-24 10:20
25
0
努力奋都ING~~~~~!
游客
登录 | 注册 方可回帖
返回