How to study C && ASM Code(6)
2007-04-09 21:39
429 查看
Download:
http://www.cisrg.cn/doc/lesson6.rar
==www.cisrg.cn==
How to study C && ASM Code(6)
|=---------------=[ 逆向函数 ]=------------------------------------=|
|=-----------------------------------------------------------------=|
|=---------------=[ 7all<7all7_at_163.com> ]=----------------------=|
|=-----------------------------------------------------------------=|
|=---------------=[ 版权所有:www.cisrg.cn ]=-----------------------=|
--[ Let's go go...
第五节《字符输入/输出的逆向》不会再出现在这个世界上了,因为就在他还
在他妈的肚子里面准备出世的时候,被我无情的扼杀了,因为我觉得他生活在
这个世界上没有任何的意义。
函数就是一组根据某种规则封装起来的程序片断(功能模块),一般C的代码
都是通过函数来组合起来的,当然你也可以不使用函数,那样的话如果你写一段
2000行的C代码的话,一定是一件很有意思的事情。
函数的逆向在该节我们直采取两种做法,即根据汇编代码逆向为C代码,然后根
据C代码逆向到汇编代码实现。在纯粹的汇编下面,一般使用过程来实现C下面类似
函数的东东,但是因为这里我们没有准备使用汇编编译器编译完整的汇编代码,因
此我们还是会以C的风格来实现被我们封装在C代码里的嵌入式汇编。
--[ C到汇编的函数实现
废话少说,Coding...
好像虽然口里喊着Coding,但仅仅写了这么点代码,心里着实有些不舒服,但没有
办法,懒人或许就是懒人,永远都是如此的懒......
紧接着,逆向该代码,观察下其结构是如何实现的。
函数调用处的汇编代码:
由上面我们看到,对于C代码的逆向后的汇编代码,其压栈操作是先压入最后一个参数,
然后以此类推,直到压入第一个参数。最后call一下该函数,call与jmp指令虽然都可以
实现直接跳转,但是其用法却完全不同,在call时会自动产生堆栈平衡,然后把压入的
参数传递到函数内部进行处理。而jmp指令则是直接的跳转。这里就简单的介绍下,详细
的可参考一些汇编资料。
func函数的汇编代码:
通过上面的解释,我们知道在该函数内部的有用代码为:
于是,我很窃喜的写下了下面的代码来实现该函数:
--[ 汇编到C的逆向
汇编到C的逆向牵扯到对汇编指令的熟悉程度,当然这种方法应该从简单的逆向开始,
可以先自己写简单的汇编代码,然后再实现稍微复杂的,以此类推,直到成为“高手”
为止。
下面举例一个牛人写的汇编函数,最近还在拜读他的英文大作:)
本人懒惰,于是想了这么一个课题:
问题二:把上面的汇编代码逆向为C代码。
谁能做出来,我请谁吃包子...
--] 总结
玩笑归玩笑,在函数调用这块是需要对其流程掌握清晰的,这样在具体的跟踪
调试时,才可以对数据的流向有清晰的认识。
http://www.cisrg.cn/doc/lesson6.rar
==www.cisrg.cn==
How to study C && ASM Code(6)
|=---------------=[ 逆向函数 ]=------------------------------------=|
|=-----------------------------------------------------------------=|
|=---------------=[ 7all<7all7_at_163.com> ]=----------------------=|
|=-----------------------------------------------------------------=|
|=---------------=[ 版权所有:www.cisrg.cn ]=-----------------------=|
--[ Let's go go...
第五节《字符输入/输出的逆向》不会再出现在这个世界上了,因为就在他还
在他妈的肚子里面准备出世的时候,被我无情的扼杀了,因为我觉得他生活在
这个世界上没有任何的意义。
函数就是一组根据某种规则封装起来的程序片断(功能模块),一般C的代码
都是通过函数来组合起来的,当然你也可以不使用函数,那样的话如果你写一段
2000行的C代码的话,一定是一件很有意思的事情。
函数的逆向在该节我们直采取两种做法,即根据汇编代码逆向为C代码,然后根
据C代码逆向到汇编代码实现。在纯粹的汇编下面,一般使用过程来实现C下面类似
函数的东东,但是因为这里我们没有准备使用汇编编译器编译完整的汇编代码,因
此我们还是会以C的风格来实现被我们封装在C代码里的嵌入式汇编。
--[ C到汇编的函数实现
废话少说,Coding...
#include <stdio.h> #include <stdlib.h> int func(int x, int y); int main() { int i; i = func(2, 3); printf("i = %d/n", i); exit(0); } int func(int x, int y) { x = x + y; return x; }
好像虽然口里喊着Coding,但仅仅写了这么点代码,心里着实有些不舒服,但没有
办法,懒人或许就是懒人,永远都是如此的懒......
紧接着,逆向该代码,观察下其结构是如何实现的。
函数调用处的汇编代码:
9: i = func(2, 3); 00401038 push 3 //压入参数2 0040103A push 2 //压入参数1,至于为什么这么个压栈,这个得问问C他爸了。 0040103C call @ILT+5(_func) (0040100a)
由上面我们看到,对于C代码的逆向后的汇编代码,其压栈操作是先压入最后一个参数,
然后以此类推,直到压入第一个参数。最后call一下该函数,call与jmp指令虽然都可以
实现直接跳转,但是其用法却完全不同,在call时会自动产生堆栈平衡,然后把压入的
参数传递到函数内部进行处理。而jmp指令则是直接的跳转。这里就简单的介绍下,详细
的可参考一些汇编资料。
func函数的汇编代码:
14: int func(int x, int y) 15: { 00401080 push ebp 00401081 mov ebp,esp //建立堆栈框架 00401083 sub esp,40h 00401086 push ebx 00401087 push esi 00401088 push edi 00401089 lea edi,[ebp-40h] 0040108C mov ecx,10h 00401091 mov eax,0CCCCCCCCh 00401096 rep stos dword ptr [edi] //以上代码为维持堆栈平衡的自生成代码, //前面的文章有较详细的介绍。 16: x = x + y; /* 这里的ebp+8正好为0x02,即前面调用func函数是的第一个参数; ebp=c正好为0x03,即前面调用func函数的第二个参数; 为什么直接的push 3;push 2会存储在ebp+8和ebp+c处呢? 这里我们需要回到前面进行分析了:) 在EIP执行到0040103C call @ILT+5(_func) (0040100a)这条 指令,且还没有执行进入func函数内部时,此时由于我们采取了 push 3; push 2; 这样的压栈操作,因此此时ESP的数据应该为,(ESP->0x0012FF28) 02 00 00 00 03 00 00 00 我们按F11,会进入func函数内部,只要一进入func函数内部,程序会自动把 执行完func函数后的下一条指令压入ESP内,为什么要把 0040103C call @ILT+5(_func) (0040100a)的下条语句保存到ESP内呢? Intel考虑的很周全,这样的话在函数调用ret返回时,就可以取出这条指令交给 EIP,这样EIP就可以自动执行了。如果此时进入函数内部的地址被覆盖或者发生 错误,在函数调用ret指令返回时,就会发生错误,这也是缓冲区溢出的利用办法:) 我们观察下此时ESP的值:(ESP->0x0012FF24) 41 10 40 00 02 00 00 00 03 00 00 00 如果你有疑问的话,你可以去查下00401041这个地址,该地址正好在call func的 下条指令:)这里这条指令为: 00401041 add esp,8 备注:如果你编译后,地址可能会改变,不会是00401041,但是你记住在进入函数内 时观察下压入ESP的值就可以知道你自己的地址是什么了。 此时,esp+4=0x02,esp+8=0x03。 OK,如果你明白了这里,就继续看是如何实现把ESP的值给EBP了,也就是如何实现把 push进来的参数以ebp+8、ebp+c的形式来使用。如果你以上内容看不明白,那么可以 到FAQ版块去提问,如果提问还是不会,那么你可以给我mail,如果还是不会,请自行 jmp 黄河。 Let's go... 前面我说过,在刚进入函数内部时的push ebp...等的操作是为了维持堆栈平衡的, 虽然的确如此,但这里我们需要使用下他们了。我们看下函数刚进来时候的汇编代码: 00401080 push ebp 00401081 mov ebp,esp 00401083 sub esp,40h 首先,在0x00401080地址处push ebp,这里既然push了ebp,我们假设此时ebp值为 0x0012FF80,那么当执行到00401081 mov ebp,esp这条语句时,此时ESP的数据应该 为: 80 FF 12 00 41 10 40 00 02 00 00 00 03 00 00 00 其次,在0x00401081地址处mov ebp,esp,原则上来说此时ebp与esp的值是相同的,也即 此时EBP的数据分布为: 80 FF 12 00 41 10 40 00 02 00 00 00 03 00 00 00 由于在0x00401083至0x00401098之间的这块代码,没有再改变EBP的值,因此此时EBP-8处 正好为0x02,而EBP-C处的值正好为0x03。 OK,到这里该明白为啥下面的语句是 mov eax, ebp+8了吧?再不明白自己去自贡吧(女生 除外,即使你想也没有这个可能了....) */ 00401098 mov eax,dword ptr [ebp+8] 0040109B add eax,dword ptr [ebp+0Ch] //看章节4可知道这里的用法:) 0040109E mov dword ptr [ebp+8],eax 17: return x; 004010A1 mov eax,dword ptr [ebp+8] //对计算的结果准备ret 18: } 004010A4 pop edi 004010A5 pop esi 004010A6 pop ebx /* 问题一: 此处为什么要使用这个语句? 答对者可获取请我吃饭的权力...突然感觉自己很无耻的说。 不过理解了这里还是对理解函数内部有帮助的,不会的可以提问下。 */ 004010A7 mov esp,ebp 004010A9 pop ebp 004010AA ret
通过上面的解释,我们知道在该函数内部的有用代码为:
00401098 mov eax,dword ptr [ebp+8] 0040109B add eax,dword ptr [ebp+0Ch] //看章节4可知道这里的用法:) 0040109E mov dword ptr [ebp+8],eax 17: return x; 004010A1 mov eax,dword ptr [ebp+8] //对计算的结果存储
于是,我很窃喜的写下了下面的代码来实现该函数:
//完整代码可下载所附带文档 int func (int x, int y) { __asm{ mov eax, x; add eax, y; mov x, eax; } return x; }
--[ 汇编到C的逆向
汇编到C的逆向牵扯到对汇编指令的熟悉程度,当然这种方法应该从简单的逆向开始,
可以先自己写简单的汇编代码,然后再实现稍微复杂的,以此类推,直到成为“高手”
为止。
下面举例一个牛人写的汇编函数,最近还在拜读他的英文大作:)
; itoaproc(source, dest) ; convert integer (source) to string of 6 characters at given destination address itoaproc PROC NEAR32 push ebp ; save base pointer mov ebp, esp ; establish stack frame push eax ; Save registers push ebx ; used by push ecx ; procedure push edx push edi pushf ; save flags mov ax, [ebp+12] ; first parameter (source integer) mov edi, [ebp+8] ; second parameter (dest offset) ifSpecial: cmp ax,8000h ; special case -32,768? jne EndIfSpecial ; if not, then normal case mov BYTE PTR [edi],'-' ; manually put in ASCII codes mov BYTE PTR [edi+1],'3' ; for -32,768 mov BYTE PTR [edi+2],'2' mov BYTE PTR [edi+3],'7' mov BYTE PTR [edi+4],'6' mov BYTE PTR [edi+5],'8' jmp ExitIToA ; done with special case EndIfSpecial: mov dx, ax ; save source number mov al,' ' ; put blanks in mov ecx,5 ; first five cld ; bytes of rep stosb ; destination field mov ax, dx ; copy source number mov cl,' ' ; default sign (blank for +) IfNeg: cmp ax,0 ; check sign of number jge EndIfNeg ; skip if not negative mov cl,'-' ; sign for negative number neg ax ; number in AX now >= 0 EndIfNeg: mov bx,10 ; divisor WhileMore: mov dx,0 ; extend number to doubleword div bx ; divide by 10 add dl,30h ; convert remainder to character mov [edi],dl ; put character in string dec edi ; move forward to next position cmp ax,0 ; check quotient jnz WhileMore ; continue if quotient not zero mov [edi],cl ; insert blank or "-" for sign ExitIToA: popf ; restore flags and registers pop edi pop edx pop ecx pop ebx pop eax pop ebp ret 6 ;exit, discarding parameters itoaproc ENDP
本人懒惰,于是想了这么一个课题:
问题二:把上面的汇编代码逆向为C代码。
谁能做出来,我请谁吃包子...
--] 总结
玩笑归玩笑,在函数调用这块是需要对其流程掌握清晰的,这样在具体的跟踪
调试时,才可以对数据的流向有清晰的认识。
相关文章推荐
- How to study C && ASM Code(3)
- How to study C && ASM Code(4)
- How to study C && ASM Code(1)
- How to study C && ASM Code(2)
- how to change the machine code to ASM by Using OllyDbg
- How to solve “add/remove operation is impossible, because the code element 'Cxxx' is read only”
- Java02 How to run Java's code
- How to use "vi" edit the docs or source code files
- Greg Hoglund, Gary McGraw, «Exploiting Software: How to Break Code»
- How to search for a taglib's code (from wiki)
- How To Create An ASM Diskgroup Using XML code Thru ASMCMD?
- How to load "CodedUItestmethod" in another "consoleapplication".
- C Language Study - how to use '#'
- How to hide & unhide the grid from the page by using people code?
- How To Create An ASM Diskgroup Using XML code Thru ASMCMD [ID 1290550.1]
- ASM ClassReader failed to parse class file - probably due to a new Java class file version that isn'
- how to do with a slow oracle dat…
- How to sign a Driver by Windows …
- Siebel Tools: How to program Browser Script &amp; Server Script
- Howto resolve the "df -h" error in android