`
driftcloudy
  • 浏览: 132217 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

OD一段简单的C++代码

    博客分类:
  • OD
阅读更多

开始学习逆向,从熟悉的js、php跳跃到汇编,有点小凌乱 ...

 

先来OD一段简单的C++代码:

#include <string.h>
#include <windows.h>
#include <stdio.h>

int funcA(int a, int b);

void main()
{
	int a;
	int b;
	int n;

	a = strlen("abc");
	b = 10;
	n = funcA(a, b);
}

int funcA(int a, int b)
{
	int c;
	char sBuff[10];

	c = (a + b) * a * b;

	sprintf(sBuff, "%d", c);
	MessageBox(NULL, sBuff, NULL, MB_OK);
	return c;
}
 

编译环境:VC6 ,release

 

这段代码逻辑上很简单,一共两个函数,main和funcA,funcA会在main中被调用一次。main函数的入口会被编译成call 00401000,00401000是虚拟的偏移量。虚拟地址也可写作“段:偏移量”的形式 ,一般来说可以不用关注段,因为同一个程序在不同的系统下,段值可能不相同。但是偏移量却是有着一些共性,对于同一个程序的某条指令,在不同系统中它的偏移量一般是相同的。按照VS的默认设置,编译出的exe文件基地址是00400000,dll文件基地址是10000000。

 

 

先来直接在main的入口处下断,然后逐步跟进。

 

00401154  |.  50                       push    eax
00401155  |.  FF35 0C994000  push    dword ptr [40990C]
0040115B  |.  FF35 08994000  push    dword ptr [409908]
00401161  |.  E8 9AFEFFFF       call    00401000

00401166  |.  83C4 0C             add     esp, 0C

 

这是一个典型的函数调用,只不过调的是main罢了。三个参数压栈,然后call,完了消栈,格式很清晰。

main中的汇编代码如下:

 

00401000  /$  57                       push    edi
00401001  |.  BF 30704000       mov     edi, 00407030                    ;  ASCII "abc"
00401006  |.  83C9 FF               or      ecx, FFFFFFFF
00401009  |.  33C0                    xor     eax, eax
0040100B  |.  F2:AE                   repne   scas byte ptr es:[edi]
0040100D  |.  F7D1                    not     ecx
0040100F  |.  49                        dec     ecx
00401010  |.  6A 0A                   push    0A
00401012  |.  51                        push    ecx
00401013  |.  E8 08000000       call    00401020                             ;  该处调用funcA函数
00401018  |.  83C4 08              add     esp, 8
0040101B  |.  5F                        pop     edi
0040101C  \.  C3                       retn

 

strlen函数并没有向funcA一样被编译为另外一个call,而是直接编译在了main函数之中。strlen的实现非常之精妙:

这是strlen()在VC优化编译模式下编译后的代码:

00401000  /$  57                       push    edi      ;  因为后面repne的时候要发生更改,所以先暂存edi

00401006  |.  83C9 FF               or      ecx, FFFFFFFF
00401009  |.  33C0                    xor     eax, eax
0040100B  |.  F2:AE                   repne   scas byte ptr es:[edi]
0040100D  |.  F7D1                    not     ecx
0040100F  |.  49                        dec     ecx

 

edi是指向字符串“abc”的指针,repne   scas byte ptr es:[edi] 指令会扫描字符串“abc”(在内存中为 61 62 63 00),从字母a开始,一直到字符串结束符,一共4个字符。

 

REPNE :用在CMPS、SCAS指令前,每执行一次串操作指令ECX减1,并判断ZF标志是否为1,只要CX=0或ZF=1,则重复执行结束。

SCAS :将附加段中的字节或字内容与AL/AX寄存器内容进行比较,根据比较的结果设置标志,每次比较后修改EDI寄存器的值,使之指向下一个元素。

 

这里需要扫描4次,每次扫描的字符与eax中的低八8位即00相比较,如果相同,则ZF标志位变成1,扫描结束;如果不同,则ecx减1并继续扫描。因此需要事先将eax置0,并且ecx置为-1。扫描完之后的ecx变为FFFFFFFB。取反后变成00000004,这是包含了字符串结束标志的长度,因此还需要减1.

 

随后将10、3入栈,准备调用funcA函数。函数的调用基本上都满足_stdcall约定 ,即参数从右向左,顺次压栈,函数调用的返回值保存在eax函数中。funcA的汇编码如下:

 

虽然有点长,但是代码还是很好理解的。

开始的两句mov是去栈中取操作数3、10,并且分别存放到eax、ecx中。

随后,sub esp,0xC是将栈顶向上移动,从而开辟出一块空的区域,可以用作预留用。

 

0040102C  |.  8D3408        lea esi,dword ptr ds:[eax+ecx]
0040102F  |.  0FAFF0        imul esi,eax
00401032  |.  0FAFF1        imul esi,ecx

这三句完成了 c = (a + b) * a * b ,运算结果的值保存在esi中。

随后调用的MessageBox的过程暂时忽略。

因为最后需要返回c的值,因此在retn之前,需要执行一句mov eax,esi。

 

这里的call调用都没有被编译成经典的:

PUSH ebp
MOV ebp esp

······

这个无所谓,值得注意的是需要确保栈的平衡性,即入栈一定要与消栈相对应。

 

 

 

分享到:
评论
3 楼 RednaxelaFX 2011-04-28  
driftcloudy 写道
嘿嘿,现在回忆起来,原来你早就玩OD了,可惜当时我一窍不通...石化 >_<

想当年啊诶诶…
2 楼 driftcloudy 2011-04-28  
RednaxelaFX 写道
这跟编译参数相关。开了FPO的话就不使用EBP作为frame pointer,就省下了这段代码。


喔哦~果然是这样...感谢指点
实验了一下,加上 /Oy- 进行编译,立马变成了我熟悉的形式
引用

push    ebp
mov     ebp, esp
sub     esp, 0C
mov     eax, dword ptr [ebp+8]
……
mov     esp, ebp
pop     ebp
retn


而 /Oy 的时候是
引用

mov     eax, dword ptr [esp+4]
mov     ecx, dword ptr [esp+8]
sub     esp, 0C
……
add     esp, 0C
retn


嘿嘿,现在回忆起来,原来你早就玩OD了,可惜当时我一窍不通...石化 >_<
1 楼 RednaxelaFX 2011-04-28  
driftcloudy 写道
这里的call调用都没有被编译成经典的:
PUSH ebp
MOV ebp esp

这跟编译参数相关。开了FPO的话就不使用EBP作为frame pointer,就省下了这段代码。
引用
/Oy[-] enable frame pointer omission

相关推荐

    c/c++源代码网站

    Dobb’s Journal** (http://www.ddj.com/code/ddj.html):著名的编程杂志DDJ的源代码部分,包含高质量的C/C++代码示例。 8. **CProgramming.com** (http://www.cprogramming.com/cgi-bin/source/source.cgi):C和...

    od语言特征点

    下面是一段 VC++ 的汇编代码示例: ```assembly 55 PUSHEBP ; 保存基址寄存器 8BEC MOVEBP,ESP ; 将栈顶指针赋值给基址寄存器 83EC44 SUBESP,44 ; 减少栈空间 56 PUSHESI ; 保存 ESI 寄存器 ``` 这段代码同样涉及到...

    C++源码网站

    5. **DANIEWEB (http://www.daniweb.com/code/c.html)**:DANIEWEB提供实用的C和C++代码段,适合初学者和有经验的开发者。 6. **Programmer's Heaven (http://www.programmersheaven.com/tags/C/)**:该网站为C编程...

    华为OD机试C卷- 伐木工(Java & JS & Python & C & C++).md-私信看全套OD代码及解析

    ### 华为OD机试C卷 - 伐木工题目详解与实现 #### 题目背景 在软件开发行业中,特别是在技术岗位的面试中,动态规划问题是常考的难点之一。华为作为全球领先的信息与通信技术解决方案提供商,其招聘过程中会设计一...

    50个代码下载网站非常好

    文章标题“50个代码下载网站非常好”以及描述“里面有百个很强大的代码资源下载网站 很实用 很好”,表明这是一篇介绍高质量C/C++代码资源下载站点的文章。这些网站提供了丰富的C/C++源代码资源,对于学习和从事C/...

    华为面试编程题整理c c++

    此段代码演示了通过指针传递参数并修改原始数据的概念。`func2`函数接受一个整型指针`pb`,并为它分配内存并赋值。然而,由于`pb`并未在`func1`中被正确初始化或捕获,导致了内存泄漏问题。 ### 5. 引用传递 当...

    WIN764系统能用的OD

    1. **安装必要的运行库**:确保系统中安装了所有必需的Microsoft Visual C++运行库,因为一些OD版本可能依赖这些库。 2. **检查系统兼容模式**:将OD设置为以兼容模式运行,比如设置为Windows XP Service Pack 3,...

    50个老鸟常去的C源代码网站

    11. **CodePedia (http://www.codepedia.com/1/C/)**:一个包含大量C/C++代码示例的数据库,适合快速查找代码和学习新概念。 12. **Temple University CSIS (http://www.cis.temple.edu/~ingargio/cis71/code/)**:...

    OllyICE,od

    OllyDbg 可以扫描Object文件/库(包括 OMF 和 COFF 格式),解压代码段[code segments]并且对其位置进行定向。 Implib扫描。 由于一些DLL文件的输出函数使用的索引号,对于人来说,这些索引号没有实际含义。如果...

    华为od-华为od练习题之字符统计-题库题解.zip

    在这个练习中,我们可能需要编写程序来统计一段文本中各字符的出现频率,包括字母、数字、标点符号等。这需要对字符串操作有深入理解,例如使用循环、条件判断、字典数据结构来实现。 1. 字符串遍历:通过for循环...

    OD插件开发实战.doc

    OD插件是用C或C++编写的一段代码,通过OD提供的API接口与调试器进行交互,实现对被调试程序的定制化操作,如数据查看、断点设置、内存读写等。 2.1.2 如何编写OD插件 编写OD插件首先需要了解OD的API函数,这些函数...

    50个C++学习网站.docx

    6. **http://www.daniweb.com/code/c.html** - DaniWeb上的C++代码段,适合初学者和专业人士学习和参考。 7. **http://www.programmersheaven.com/tags/C/** - Programmers Heaven提供了大量的C编程资源,包括教程...

    Visual C++ 编译链接信息手册

    《Visual C++ 编译链接信息手册》是针对C++编程者的一份极其重要的参考资料,尤其对于在使用Visual C++开发环境中遇到编译和链接问题的开发者来说,它提供了宝贵的解决方案。手册涵盖了一系列关于编译器选项、链接器...

    V055一树的C++端!

    从标签"OD932"来看,这可能是一个特定的项目代码或者内部标识符,但没有明确的IT行业含义,可能是开发者自定义的标签。 压缩包内的文件名称列表提供了更具体的信息: 1. **libmysql.dll**: 这是MySQL数据库的动态...

    c代码网站大全,零分下载,很好很强大

    - **特点**:提供了《Data Structures and Algorithms in C++》一书中的源代码。 - **适用场景**:适合学习数据结构和算法的学生和研究人员。 ### 18. C Snippets (http://c.snippets.org/) - **特点**:该网站专注...

    vc++ 开发实例源码包

    内部包含:mp3播放器Lrc歌词同步源程序代码分析、mp3播放器+支持歌词同步显示哦、简单音乐播放器。 mfc 解码 视频音频解码部分。 MFC_MultiSender_OVER 文件传送,多文件(超大文件)传送功能的实现,含文档。 ...

    VC命令行编译C++.docx

    《VC命令行编译C++详解》 C++编程中,使用Visual C++(VC)命令行编译器cl.exe和连接器mlink.exe是开发者常用的技术手段...通过实践和探索,我们可以根据项目需求灵活调整编译参数,从而编写出更高效、更优化的C++代码。

    小游戏—贪食蛇(附源代码)

    贪食蛇,一款经典且深受喜爱的小游戏,其简单的操作和无限的挑战性使得它在众多游戏类型中独树一帜。本文将深入探讨如何使用VC++编程语言来实现这款小游戏,带你了解游戏设计的基本原理和编程技巧。 首先,VC++是...

    郁金香VC++外挂编程全集中级篇2.1.5part01

    在接下来的一段时间将由我和大家一起学习游戏外挂的分析,制作。 课程分四个大章节 初级篇,中级篇,进阶篇,高级篇 初级篇内容:编写一个完整的,简单的外挂 C++的数据类型:Byte,Word,DWORD,int,float API函数的...

Global site tag (gtag.js) - Google Analytics