==www.cciss.cn.==
How to regard converse engineering?
|=---------------=[ 为何注重逆向工程 ]=----------------------------=|
|=-----------------------------------------------------------------=|
|=---------------=[ 7all<7all_at_cciss.cn> ]=------------------=|
|=-----------------------------------------------------------------=|
|=---------------=[ 版权所有:www.cciss.cn ]=-----------------------=|
--[ 逆向工程的定义
通过google的搜索,也没有找到合适的对于逆向工程的定义,从其起源来看,逆向工程的确
是存在了有些时间了。搜索到的很多信息大多数是针对工程术语的,有些他们的使用术语比较
使人头大:)。而这里我们想说的逆向工程是计算机领域的逆向工程,从实际意义来说,就是把
高级语言写的程序,在看完其反编译的汇编代码后,根据汇编代码再反向写回到高级语言的程
序表达方式。例如:我们拿C、C++等写的程序,编译完后是汇编代码/机器码,我们在不知道
源代码的情况下,只能看到汇编代码,于是只能从汇编代码去读程序的那个模块使用了那种功
能,这样我们就可以根据我们阅读汇编代码的情况,对程序进行逆向,然后把程序再用C、C++
的形式进行重写。
当然,上面说的这个办法比较过于繁琐,为了逆向的简单性,我们可以采取在知道了汇编代
码对应的C程序功能后,直接使用C内嵌汇编的方式实现我们对源程序的逆向过程。
简单来说,逆向工程可以具体如下的一个流程:
A: 高级语言程序(C、C++、...)-->编译-->生成可执行程序(机器码/汇编语言)
B: 可执行程序-->反编译(IDA、WIN32DASM等反编译软件)-->汇编代码
C: 汇编代码-->分析、了解汇编代码程序流程-->进行逆向或者实现某个功能
D: 逆向工程完毕
--[ 如何学习逆向工程?
首先需要的就是要对汇编语言有一些了解,因为在我们对程序反编译完后,我们看到的只是汇编
代码,所以对汇编语言必须要有一定的了解,甚至是精通。
其次,熟悉高级语言的编程,例如C、C++,只有这样才能更好的在我们的逆向过程中去发现更多的
乐趣。
最后,自己多写程序多测试,只有这样才能积累更扎实的基础。顺便说下,我们下面的文档都是针
对C->ASM的一个逆向的过程,当然这个系列的文档不会涵盖很广的方面,但是基本的还是会有的:)
--[ 为何注重逆向工程?
逆向工程在软件破解、漏洞挖掘等技术中占据了非常重要的位置。这些技术都是和逆向工程紧密结
合的技术,没有了所谓的逆向工程的过程,很难理解一些技术怎么去做:)
--[ 简单演示
编程语言: C
调试工具: VC6
A: 源代码演示,下面的C代码很简单,myfun函数实现参数x + 参数y的计算,然后把相加的数值给z,
最后函数返回z.
/*
Author : 7all
Data : 2006-08-09
Content: 代码演示简单的逆向工程示例
*/
#include <stdio.h>
int main()
{
int i;
i = myfun(3, 4);
printf("i = %d/n/n", i);
exit(0);
}
//function
int myfun(int x, int y)
{
int z;
z = x + y;
return z;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
B: 如何逆向?(这里的部分具体办法,请参照C->ASM部分的lesson1,在这个里面详细的讲述了下.)
B-1: 调试程序,我得到了下面的反编译汇编代码:
//调用myfun函数的地方
11: i = myfun(3, 4);
00401028 push 4
0040102A push 3
0040102C call @ILT+5(_myfun) (0040100a)
//myfun函数
16: int myfun(int x, int y)
17: {
0040B760 push ebp
0040B761 mov ebp,esp
0040B763 sub esp,44h
0040B766 push ebx
0040B767 push esi
0040B768 push edi
0040B769 lea edi,[ebp-44h]
0040B76C mov ecx,11h
0040B771 mov eax,0CCCCCCCCh
0040B776 rep stos dword ptr [edi]
18: int z;
19: z = x + y;
0040B778 mov eax,dword ptr [ebp+8]
0040B77B add eax,dword ptr [ebp+0Ch] //这里在操作的时候是赋值给了eax寄存器
0040B77E mov dword ptr [ebp-4],eax
20: return z;
0040B781 mov eax,dword ptr [ebp-4]
21: }
0040B784 pop edi
0040B785 pop esi
0040B786 pop ebx
0040B787 mov esp,ebp
0040B789 pop ebp
0040B78A ret
从上面汇编代码看,我们看到了myfun函数的汇编代码过程,以及我们的C程序中调用myfun函数的地方.
下面我们把这个C程序拿汇编反编译下.
B-2: 重构汇编代码,实现与C代码相同的功能.
首先,我们把i = myfun(3, 4);这里的C格式的函数调用转变为汇编格式,代码示例如下:
pusha;
push 0x04;
push 0x03;
call myfun;
mov i,eax;
popa;
其次,我们把myfun函数转换为汇编格式,代码示例如下:
int myfun(int x, int y)
{
__asm{
xor eax,eax;
xor ebx,ebx;
mov eax,x;
mov ebx,y;
add eax,ebx;
}
}
最后,我们把上面书写的C代码转变为我们逆向后的汇编代码,实现的功能与C格式的完全相同:)示例如下:
/*
Author : 7all
Data : 2006-08-09
Content: 代码演示简单的逆向工程示例
*/
#include <stdio.h>
int myfun(int x, int y);
int main()
{
static int i;
__asm{
pusha;
push 0x04;
push 0x03;
call myfun;
mov i,eax; //这里把eax的值给i变量.eax的值也正是myfun函数计算后的返回值
popa;
}
printf("i = %d/n/n", i);
exit(0);
}
int myfun(int x, int y)
{
__asm{
xor eax,eax;
xor ebx,ebx;
mov eax,x;
mov ebx,y;
add eax,ebx;
}
}
B-3: 分析
我们看到B-2步骤最终生成了一段汇编格式的程序,但是这段代码实现的功能与我们的C代码实现的功
能完全相同.因为上面的C代码是我们事先写好,然后调试反编译汇编代码出来的,所以在这里的逆向难免
会受到原来C代码的影响.
Now,我们假设我们只能得到下面的汇编代码,然后我们怎么去分析并重构C程序实现的功能呢?我想有些
同志看到上面的逆向过程后难免会感觉头大.这个...没有关系,我们在这节分析下为什么我们会在以上步
骤去这样做那样做,最终才实现了逆向的过程的.OK,Let's go:)
记住,下面的步骤全部是假设我们看不到C源代码的前提下进行的静态汇编代码分析(没有跟踪调试).
首先,我们先看下myfun函数反编译后的汇编代码,代码如下:
0040B760 push ebp------|
0040B761 mov ebp,esp--|->创建堆栈框架,这里就不用看了.
0040B763 sub esp,44h--|
0040B766 push ebx------|
0040B767 push esi------|->大家可能注意到了,这里push进来
0040B768 push edi------| 的最后都pop出去了,维持堆栈平衡的DD.
0040B769 lea edi,[ebp-44h]---|
0040B76C mov ecx,11h---------|->通过我们的静态观察,发现
0040B771 mov eax,0CCCCCCCCh--|一直到这里的汇编代码...
0040B776 rep stos dword ptr [edi]-|全TMD是罗嗦的代码.
0040B778 mov eax,dword ptr [ebp+8]----|->这四行才是程序真正要实现的功能:)
0040B77B add eax,dword ptr [ebp+0Ch]--|->前面的那些代码,我们静态观察罗嗦代码占的比例很
0040B77E mov dword ptr [ebp-4],eax----|大:)当然,实际情况可能不同,但是静态分析汇编代
0040B781 mov eax,dword ptr [ebp-4]----|码的关键就是先排除一些乱七八糟的代码:)
0040B784 pop edi------|
0040B785 pop esi------|
0040B786 pop ebx------|->释放堆栈框架
0040B787 mov esp,ebp--|
0040B789 pop ebp------|
0040B78A ret
通过我们上面对myfun函数汇编代码的静态分析,我把注意力集中在了中间的那四行,这四行进行了某些操作:)
0040B778 mov eax,dword ptr [ebp+8]---->eax赋值
0040B77B add eax,dword ptr [ebp+0Ch]-->eax=eax+[ebp+0xc]
0040B77E mov dword ptr [ebp-4],eax---->[ebp-4]=eax--|->这里也为废话
0040B781 mov eax,dword ptr [ebp-4]---->eax=[ebp-4]--|
大家看后两行代码,显然这里的汇编代码是没有优化过的汇编代码.很简单,本身eax进行了add(加法)操作
后,就已经是一个数值了.可是,偏偏又加了这么两步,至少生成的可执行程序又增加了那么几字节的大小,
千万别小看这么几个字节,如果你的程序是数万行的代码,而生成的可执行程序(即汇编代码),在汇编代码
中每个地方都加这么几个字节,那可能就是几K.其实几K吧,也没有什么了不起的,但是如果是木马 Or 病毒
Or 后门程序的话,那么我相信几K的代码还是蛮严重的.
所以,这里顺便提醒大家,在最终编译程序的时候,别忘记使用编译选项来尽量的优化代码:)
其次,我们来分析下myfun函数调用的汇编代码,汇编代码如下:
push 4 //压4入ESP
push 3 //压3入ESP
call myfun (0040100a) //调用函数
看到这里,我们不得不突然间想到上面我们对myfun函数的静态分析中,提取出来的感觉比较关键的汇编代码.
myfunc函数提取的关键汇编代码:
0040B778 mov eax,dword ptr [ebp+8]---->eax赋值
0040B77B add eax,dword ptr [ebp+0Ch]-->eax=eax+[ebp+0xc]
0040B77E mov dword ptr [ebp-4],eax---->[ebp-4]=eax
0040B781 mov eax,dword ptr [ebp-4]---->eax=[ebp-4]
上面在调用myfun函数时,采用了压入ESP的办法.而这里是
mov eax,dword ptr [ebp+8] //哈哈,ebp+8 = esp + 4 = 4.
同理,[ebp+0Ch] = esp + 8 = 3.
add eax,dword ptr [ebp+0Ch] //这里也就是进行了一个加法运算,最后得到的结果肯定是7
然后eax最后的结果也为7:)
可能有人问,为什么ebp+8 = esp + 4 ? 这个问题留给以后的文档里面吧:)我们慢慢来.
第三,我们根据上面提取的myfun函数的关键汇编代码来还原myfun函数.
我们看调用myfun函数时,是push了两个值进入myfun函数,那么我们就可以判断myfun函数有两个参数.
然后,myfun函数有一个加法运算后的返回值给了eax寄存器.这样看来,我们基本知道了myfun函数的
基本信息了.
1: myfun函数有两个参数
2: myfun函数有返回值
3: myfun函数进行了int类型的数值操作
ok,根据上面的基本信息,我们先来重构下myfun函数:)
int myfun(int a, int b)//记住,C的参数在汇编的压入是后进的格式,即先压入b,再压入a
{
xor eax,eax
xor ebx,ebx //其实也可以不使用xor汇编指令,但是我想要大家养成一个习惯,以后写shellcode会方便:)
mov eax,a
mov ebx,b
add eax,ebx
}
最后,我们根据前面的静态分析过程,再次的重构下整个的代码:)
push 4
push 3
call myfun
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int myfun(int a, int b)//记住,C的参数在汇编的压入是后进的格式,即先压入b,再压入a
{
xor eax,eax
xor ebx,ebx //其实也可以不使用xor汇编指令,但是我想要大家养成一个习惯,以后写shellcode会方便:)
mov eax,a
mov ebx,b
add eax,ebx
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
根据上面的函数调用和函数逆向,我们感觉这样的静态分析结果,逆向出的代码是可以实现C程序代码功能的.
感觉是永远会欺骗人的东西,要想感觉成为现实,还是需要测试结果的.
下面还有一个问题,我们的C代码在调用printf函数时,使用了int i这个int类型变量,而这个i正是我们获取
myfun函数返回值的变量,其实到这里已经没有什么难题了.我们把前面的调用myfun函数的汇编代码稍微调
整一下下就可以了:)代码如下:
push 4
push 3
call myfun
mov i,eax //因为eax寄存器在函数myfun内部是存在加法运算和的寄存器,这样i就是最后的计算结果了:)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
整理代码如下:(其实和上面我们的那个代码是相同的:))
//函数调用及保存函数返回值
__asm{
push 4
push 3
call myfun
mov i,eax
}
//myfun函数的重构
int myfun(int a, int b)
{
__asm{
xor eax,eax
xor ebx,ebx
mov eax,a
mov ebx,b
add eax,ebx //这里eax保存了myfun函数计算后的返回值.
}
}
马上把这个代码copy到程序中做下测试,看看功能是否和我刚开始写的那个C代码实现的功能完全一致?
--[总结
本来想把这个章节写的内容多些,但是写来写去也不会太多了.因为意思就这么些,大家顺便的一看,就
知道学习逆向工程的重要性了:)
对于文章中提到的一些调试的具体办法,请参考lesson1文档,在lesson1文档内我做了图片格式的注释.
--[ 参考资料
Intel汇编指令格式 www.intel.com
C程序设计
<<How To Study C & ASM code(1)>>: http://bbs.cciss.cn/viewtopic.php?id=5
How to regard converse engineering?
|=---------------=[ 为何注重逆向工程 ]=----------------------------=|
|=-----------------------------------------------------------------=|
|=---------------=[ 7all<7all_at_cciss.cn> ]=------------------=|
|=-----------------------------------------------------------------=|
|=---------------=[ 版权所有:www.cciss.cn ]=-----------------------=|
--[ 逆向工程的定义
通过google的搜索,也没有找到合适的对于逆向工程的定义,从其起源来看,逆向工程的确
是存在了有些时间了。搜索到的很多信息大多数是针对工程术语的,有些他们的使用术语比较
使人头大:)。而这里我们想说的逆向工程是计算机领域的逆向工程,从实际意义来说,就是把
高级语言写的程序,在看完其反编译的汇编代码后,根据汇编代码再反向写回到高级语言的程
序表达方式。例如:我们拿C、C++等写的程序,编译完后是汇编代码/机器码,我们在不知道
源代码的情况下,只能看到汇编代码,于是只能从汇编代码去读程序的那个模块使用了那种功
能,这样我们就可以根据我们阅读汇编代码的情况,对程序进行逆向,然后把程序再用C、C++
的形式进行重写。
当然,上面说的这个办法比较过于繁琐,为了逆向的简单性,我们可以采取在知道了汇编代
码对应的C程序功能后,直接使用C内嵌汇编的方式实现我们对源程序的逆向过程。
简单来说,逆向工程可以具体如下的一个流程:
A: 高级语言程序(C、C++、...)-->编译-->生成可执行程序(机器码/汇编语言)
B: 可执行程序-->反编译(IDA、WIN32DASM等反编译软件)-->汇编代码
C: 汇编代码-->分析、了解汇编代码程序流程-->进行逆向或者实现某个功能
D: 逆向工程完毕
--[ 如何学习逆向工程?
首先需要的就是要对汇编语言有一些了解,因为在我们对程序反编译完后,我们看到的只是汇编
代码,所以对汇编语言必须要有一定的了解,甚至是精通。
其次,熟悉高级语言的编程,例如C、C++,只有这样才能更好的在我们的逆向过程中去发现更多的
乐趣。
最后,自己多写程序多测试,只有这样才能积累更扎实的基础。顺便说下,我们下面的文档都是针
对C->ASM的一个逆向的过程,当然这个系列的文档不会涵盖很广的方面,但是基本的还是会有的:)
--[ 为何注重逆向工程?
逆向工程在软件破解、漏洞挖掘等技术中占据了非常重要的位置。这些技术都是和逆向工程紧密结
合的技术,没有了所谓的逆向工程的过程,很难理解一些技术怎么去做:)
--[ 简单演示
编程语言: C
调试工具: VC6
A: 源代码演示,下面的C代码很简单,myfun函数实现参数x + 参数y的计算,然后把相加的数值给z,
最后函数返回z.
/*
Author : 7all
Data : 2006-08-09
Content: 代码演示简单的逆向工程示例
*/
#include <stdio.h>
int main()
{
int i;
i = myfun(3, 4);
printf("i = %d/n/n", i);
exit(0);
}
//function
int myfun(int x, int y)
{
int z;
z = x + y;
return z;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
B: 如何逆向?(这里的部分具体办法,请参照C->ASM部分的lesson1,在这个里面详细的讲述了下.)
B-1: 调试程序,我得到了下面的反编译汇编代码:
//调用myfun函数的地方
11: i = myfun(3, 4);
00401028 push 4
0040102A push 3
0040102C call @ILT+5(_myfun) (0040100a)
//myfun函数
16: int myfun(int x, int y)
17: {
0040B760 push ebp
0040B761 mov ebp,esp
0040B763 sub esp,44h
0040B766 push ebx
0040B767 push esi
0040B768 push edi
0040B769 lea edi,[ebp-44h]
0040B76C mov ecx,11h
0040B771 mov eax,0CCCCCCCCh
0040B776 rep stos dword ptr [edi]
18: int z;
19: z = x + y;
0040B778 mov eax,dword ptr [ebp+8]
0040B77B add eax,dword ptr [ebp+0Ch] //这里在操作的时候是赋值给了eax寄存器
0040B77E mov dword ptr [ebp-4],eax
20: return z;
0040B781 mov eax,dword ptr [ebp-4]
21: }
0040B784 pop edi
0040B785 pop esi
0040B786 pop ebx
0040B787 mov esp,ebp
0040B789 pop ebp
0040B78A ret
从上面汇编代码看,我们看到了myfun函数的汇编代码过程,以及我们的C程序中调用myfun函数的地方.
下面我们把这个C程序拿汇编反编译下.
B-2: 重构汇编代码,实现与C代码相同的功能.
首先,我们把i = myfun(3, 4);这里的C格式的函数调用转变为汇编格式,代码示例如下:
pusha;
push 0x04;
push 0x03;
call myfun;
mov i,eax;
popa;
其次,我们把myfun函数转换为汇编格式,代码示例如下:
int myfun(int x, int y)
{
__asm{
xor eax,eax;
xor ebx,ebx;
mov eax,x;
mov ebx,y;
add eax,ebx;
}
}
最后,我们把上面书写的C代码转变为我们逆向后的汇编代码,实现的功能与C格式的完全相同:)示例如下:
/*
Author : 7all
Data : 2006-08-09
Content: 代码演示简单的逆向工程示例
*/
#include <stdio.h>
int myfun(int x, int y);
int main()
{
static int i;
__asm{
pusha;
push 0x04;
push 0x03;
call myfun;
mov i,eax; //这里把eax的值给i变量.eax的值也正是myfun函数计算后的返回值
popa;
}
printf("i = %d/n/n", i);
exit(0);
}
int myfun(int x, int y)
{
__asm{
xor eax,eax;
xor ebx,ebx;
mov eax,x;
mov ebx,y;
add eax,ebx;
}
}
B-3: 分析
我们看到B-2步骤最终生成了一段汇编格式的程序,但是这段代码实现的功能与我们的C代码实现的功
能完全相同.因为上面的C代码是我们事先写好,然后调试反编译汇编代码出来的,所以在这里的逆向难免
会受到原来C代码的影响.
Now,我们假设我们只能得到下面的汇编代码,然后我们怎么去分析并重构C程序实现的功能呢?我想有些
同志看到上面的逆向过程后难免会感觉头大.这个...没有关系,我们在这节分析下为什么我们会在以上步
骤去这样做那样做,最终才实现了逆向的过程的.OK,Let's go:)
记住,下面的步骤全部是假设我们看不到C源代码的前提下进行的静态汇编代码分析(没有跟踪调试).
首先,我们先看下myfun函数反编译后的汇编代码,代码如下:
0040B760 push ebp------|
0040B761 mov ebp,esp--|->创建堆栈框架,这里就不用看了.
0040B763 sub esp,44h--|
0040B766 push ebx------|
0040B767 push esi------|->大家可能注意到了,这里push进来
0040B768 push edi------| 的最后都pop出去了,维持堆栈平衡的DD.
0040B769 lea edi,[ebp-44h]---|
0040B76C mov ecx,11h---------|->通过我们的静态观察,发现
0040B771 mov eax,0CCCCCCCCh--|一直到这里的汇编代码...
0040B776 rep stos dword ptr [edi]-|全TMD是罗嗦的代码.
0040B778 mov eax,dword ptr [ebp+8]----|->这四行才是程序真正要实现的功能:)
0040B77B add eax,dword ptr [ebp+0Ch]--|->前面的那些代码,我们静态观察罗嗦代码占的比例很
0040B77E mov dword ptr [ebp-4],eax----|大:)当然,实际情况可能不同,但是静态分析汇编代
0040B781 mov eax,dword ptr [ebp-4]----|码的关键就是先排除一些乱七八糟的代码:)
0040B784 pop edi------|
0040B785 pop esi------|
0040B786 pop ebx------|->释放堆栈框架
0040B787 mov esp,ebp--|
0040B789 pop ebp------|
0040B78A ret
通过我们上面对myfun函数汇编代码的静态分析,我把注意力集中在了中间的那四行,这四行进行了某些操作:)
0040B778 mov eax,dword ptr [ebp+8]---->eax赋值
0040B77B add eax,dword ptr [ebp+0Ch]-->eax=eax+[ebp+0xc]
0040B77E mov dword ptr [ebp-4],eax---->[ebp-4]=eax--|->这里也为废话
0040B781 mov eax,dword ptr [ebp-4]---->eax=[ebp-4]--|
大家看后两行代码,显然这里的汇编代码是没有优化过的汇编代码.很简单,本身eax进行了add(加法)操作
后,就已经是一个数值了.可是,偏偏又加了这么两步,至少生成的可执行程序又增加了那么几字节的大小,
千万别小看这么几个字节,如果你的程序是数万行的代码,而生成的可执行程序(即汇编代码),在汇编代码
中每个地方都加这么几个字节,那可能就是几K.其实几K吧,也没有什么了不起的,但是如果是木马 Or 病毒
Or 后门程序的话,那么我相信几K的代码还是蛮严重的.
所以,这里顺便提醒大家,在最终编译程序的时候,别忘记使用编译选项来尽量的优化代码:)
其次,我们来分析下myfun函数调用的汇编代码,汇编代码如下:
push 4 //压4入ESP
push 3 //压3入ESP
call myfun (0040100a) //调用函数
看到这里,我们不得不突然间想到上面我们对myfun函数的静态分析中,提取出来的感觉比较关键的汇编代码.
myfunc函数提取的关键汇编代码:
0040B778 mov eax,dword ptr [ebp+8]---->eax赋值
0040B77B add eax,dword ptr [ebp+0Ch]-->eax=eax+[ebp+0xc]
0040B77E mov dword ptr [ebp-4],eax---->[ebp-4]=eax
0040B781 mov eax,dword ptr [ebp-4]---->eax=[ebp-4]
上面在调用myfun函数时,采用了压入ESP的办法.而这里是
mov eax,dword ptr [ebp+8] //哈哈,ebp+8 = esp + 4 = 4.
同理,[ebp+0Ch] = esp + 8 = 3.
add eax,dword ptr [ebp+0Ch] //这里也就是进行了一个加法运算,最后得到的结果肯定是7
然后eax最后的结果也为7:)
可能有人问,为什么ebp+8 = esp + 4 ? 这个问题留给以后的文档里面吧:)我们慢慢来.
第三,我们根据上面提取的myfun函数的关键汇编代码来还原myfun函数.
我们看调用myfun函数时,是push了两个值进入myfun函数,那么我们就可以判断myfun函数有两个参数.
然后,myfun函数有一个加法运算后的返回值给了eax寄存器.这样看来,我们基本知道了myfun函数的
基本信息了.
1: myfun函数有两个参数
2: myfun函数有返回值
3: myfun函数进行了int类型的数值操作
ok,根据上面的基本信息,我们先来重构下myfun函数:)
int myfun(int a, int b)//记住,C的参数在汇编的压入是后进的格式,即先压入b,再压入a
{
xor eax,eax
xor ebx,ebx //其实也可以不使用xor汇编指令,但是我想要大家养成一个习惯,以后写shellcode会方便:)
mov eax,a
mov ebx,b
add eax,ebx
}
最后,我们根据前面的静态分析过程,再次的重构下整个的代码:)
push 4
push 3
call myfun
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int myfun(int a, int b)//记住,C的参数在汇编的压入是后进的格式,即先压入b,再压入a
{
xor eax,eax
xor ebx,ebx //其实也可以不使用xor汇编指令,但是我想要大家养成一个习惯,以后写shellcode会方便:)
mov eax,a
mov ebx,b
add eax,ebx
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
根据上面的函数调用和函数逆向,我们感觉这样的静态分析结果,逆向出的代码是可以实现C程序代码功能的.
感觉是永远会欺骗人的东西,要想感觉成为现实,还是需要测试结果的.
下面还有一个问题,我们的C代码在调用printf函数时,使用了int i这个int类型变量,而这个i正是我们获取
myfun函数返回值的变量,其实到这里已经没有什么难题了.我们把前面的调用myfun函数的汇编代码稍微调
整一下下就可以了:)代码如下:
push 4
push 3
call myfun
mov i,eax //因为eax寄存器在函数myfun内部是存在加法运算和的寄存器,这样i就是最后的计算结果了:)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
整理代码如下:(其实和上面我们的那个代码是相同的:))
//函数调用及保存函数返回值
__asm{
push 4
push 3
call myfun
mov i,eax
}
//myfun函数的重构
int myfun(int a, int b)
{
__asm{
xor eax,eax
xor ebx,ebx
mov eax,a
mov ebx,b
add eax,ebx //这里eax保存了myfun函数计算后的返回值.
}
}
马上把这个代码copy到程序中做下测试,看看功能是否和我刚开始写的那个C代码实现的功能完全一致?
--[总结
本来想把这个章节写的内容多些,但是写来写去也不会太多了.因为意思就这么些,大家顺便的一看,就
知道学习逆向工程的重要性了:)
对于文章中提到的一些调试的具体办法,请参考lesson1文档,在lesson1文档内我做了图片格式的注释.
--[ 参考资料
Intel汇编指令格式 www.intel.com
C程序设计
<<How To Study C & ASM code(1)>>: http://bbs.cciss.cn/viewtopic.php?id=5

8787

被折叠的 条评论
为什么被折叠?



