《逆向工程核心原理》笔记第一章到第十一章

摘要:
程序OD RestartCtrl+F2的基本命令重新启动调试StepIntoF7。执行的语句将进入函数。StepOverF8.执行的语句不会进入函数。ExecutettillReturnCtrl+F9在函数代码内运行,直到retn跳出(命令函数跳出)。OD右侧注释的红色部分是代码调用的API函数名。VS自动添加它,以确保程序的正常运行。
第一章/第二章 分析Hello World!程序

OD基本命令

  1. Restart Ctrl+F2 重新开始调试

  2. Step Into F7 执行语句会进入函数内部

  3. Step Over F8 执行语句不会进入函数内部

  4. Execute till Return Ctrl+F9 一直在函数代码内部运行,直到遇到retn跳出

(跳出该命令函数)

OD中右边注释中的红字部分是 代码调用的API函数名称 是VS为了保证程序正常运行自动添加的,源码中并没有,是VS的启动函数,可以暂时忽略。

RETN指令,它用于返回函数调用者的下一条命令,一般是被调用的函数的最后一句

●找到Helloworld!的main()主函数 未完成 没找到

OD调试器指令
Go toCtrl+G移动到指定地址,用来查看代码或者内存,运行时不能用
Execute till CursorF4执行到光标位置,即直接转到要调试的地址
Comment;添加注释
User-defined commet右键菜单Search for User-defined comment
Label:添加标签
User-defined label右键菜单Search for User-defined label
Set/Reset BreakPointF2设置或取消断点(BP)(BP就是断点
RunF9运行(若设置了断点,则执行至断点处)
Show the current EIP*显示当前EIP(命令指针)位置
Show the previous Cursor-显示上一个光标的位置
Preview CALL/JMP addressEnter若光标处有CALL/JMP等指令,则跟踪并显示相关地址(运行时不可用)

在菜单栏选择View-Breakpoints选项(快捷键ALT+B)打开Breakpoints窗口,该窗口列出代码中设置的断点。双击会跳到相应位置。

右键菜单Search for User-defined comment。可以看见所有添加的注释。双击会跳到相应位置。

找主函数的方法

<1>

1、 从头到尾地执行 直到消息窗口弹出 弹出消息窗口的就是主函数 F8

2、 第二遍 一直执行到弹出消息窗口的函数前 F7 进入 函数内部

<2>查找字符串

Tips

VC++中,static字符串会被默认保存为Unicode码形式,static字符串是指在程序内部被硬编码的字符串。

代码与数据所在的区域是彼此分开的。

<3>API检索

Helloworld!.exe这个程序会出弹窗

弹窗调用了user32.MessageBoxW()API

所以我们直接 右键 查找所有模块间的调用(All intermodular calls)该窗口会列出程序中调用的所有API

找 MessageBoxW()

<4>

上法的缺点: OD不能为所有.exe都列出API函数调用列表。使用压缩器/保护器工具对软件进行压缩或者保护后,文件结构机会改变。因此OD就不能列出所有API函数列表了。

Tips

压缩器:压缩软件的代码、数据、资源等,压缩后仍是.exe

保护器:不仅具有压缩功能还能反调试、反模拟、反储存..能够有效保护进程

DLL代码库被加载到进程内存后,可直接向DLL代码库添加断点。看不懂

API是操作系统对用户应用程序提供的一系列函数,实现于系统文件夹中的*.dll文件内部。

我们编写的应用程序执行某种操作时,必须使用OS提供的API向OS提出请求,然后与被调用API对应的系统DLL文件就会被加载到应用程序的进程内存。

该过程可以通过,OD菜单中的View-Memory(Alt+M),打开内存映射窗口,观察到。

若HelloWorld.exe应用程序中调用了MessageBoxW()API,则调用时程序运行到该处就会停止。

1、 OD中的Name in all modules(所有模块名称) 命令可以列出被加载的DLL文件中提供的所有API。名称排序。找到MessageBoxW。

2、 下断点 F2

3、 继续执行 F9 直到遇见MessageBoxW()代码的断点 自动停

4、 此时的ESP值对应一个返回地址 HelloWorld.exe的main()函数调用完MessageBoxW()之后,程序会回到该地址处。Ctrl+F9可以直接让MessageBoxW()到RETN处。F7也可以。

用打补丁的方式修改字符串

打补丁 可以修BUG 还可以加新功能

<1>直接修改字符串 缓冲区

右下 要选HEX/ASCII

直接智能搜索到 相应的字符串处 数据窗口跟随—>立即数

在ASCII区域选中 Ctrl+E 直接更改 保存到可执行文件 保存文件

此法的缺点在于不能比原字符串长,最好别

<2>程序中未被使用的NULL填充区域

找一块空地儿 Ctrl+E 修改

找到原字符串的地方修改汇编指令 空格键修改

把地址改成新地方的地址

保存

汇编语言基础指令
CALL XXXX调用XXXX地址处的函数
JMP XXXX跳转到XXXX地址处
PUSH XXXX保存XXXX到栈
RETN跳转到栈中保持的地址

术语和说明

VA进程的虚拟地址
OP codeCPU指令
PEwindows可执行文件(EXE、DLL、SYS等)
第三章 小端序标记法

字节序 是多字节数据在计算机内存中存放的字节顺序 主要分为 小端序 和 大端序

BYTEb=0x12
WOEDw=0x1234
DWOROdw=0x12345678
charstr[]=“abcde”

大端序与小端序的不同比较

TYPENAMESIZE大端序类型小端序类型
BYTEb1[12][12]
WOEDw2[12][34][34][12]
DWORDdw4[12][34][56][78][78][56][34][12]
char[]str6[61][62][63][64][65][00][61][62][63][64][65][00]

Tip

字符串最后是以NULL结尾的

大端序存储数据时,内存地址低位 存储 数据的高位

小端序存储数据时,内存地址高位 存储 数据的高位

小端序是高位存高位 这是一直逆序存储的方式 保持的字节顺序被倒转

字符串在字符数组里存着,字符数组在内存中是连续的,所以这个时候无论是大小端序,存储的顺序都是一样的。

第四章IA-32寄存器基本讲解

寄存器是CPU内部用来存放数据的一些小型存储区域

基本程序运行寄存器

1、 通用寄存器8 通常用来保存常量与地址

2、 段寄存器6

3、 程序状态与控制寄存器1

4、 指令指针寄存器1 EIP

16-bit32-bit
AHALAXEAX累加器(针对操作数和结果数据)
BHBLBXEBX基址寄存器(DS段中的数据指针)
CHCLCXECX计数器(字符串和循环操作)
DHDLDXEDX数据寄存器(I/O指针)
BPEBP拓展基址指针寄存器(SS段中栈内数据指针)
SIESI源变址寄存器(字符串操作源指针)
DIEDI目的变址寄存器(字符串操作目标指针)
SPESP栈指针寄存器(SS段中栈指针)

<1>通用寄存器↓

ESP指示栈区域的栈顶地址,PUSH、POP、CALL、RET指令可以直接用来操作ESP

EBP表示栈区域的基地址,函数被调用时,保存ESP的值,函数返回时再把值返回ESP,保证栈不会崩溃。(栈帧技术)。

ESI和EDI与特定指令(LODS、STOS、REP、MOVS等)一起使用,主要用于内存复制。

​ 装串 保存串 串传送

<2>段寄存器

段是一种内存保护技术,它把内存分段,保护内存。它还同

一起用于将虚拟内存变更为实际物理内存。段内存记录在SDT中,而段寄存器就持有这些SDT的索引。

段寄存器

CS代码段寄存器存放应用程序代码所在段的段基址
SS栈段寄存器存放栈段的段基址
DS数据段寄存器存放数据段的段基址
ES附加(数据)段寄存器存放程序使用的附加数据段的段基址
FS数据段寄存器同上
GS数据段寄存器同上

FS常在程序调试中用到,用于计算SEH(结构化异常处理)、TEB(线程环境块)、PEB(进程环境块)等地址。

<3>标志寄存器EFLAGS

EFLAGS(32位)是由FLAGS(16位)扩展来的。

每位值都有意义。

初级阶段掌握 ZF(零标志)、OF(溢出标志)、CF(进位标志)即可。

ZF 运算结果0或1,True或False

OF 有符号整数溢出时,OF为1。MSB改变时,其值也为1。

CF 无符号整数溢出时,CF为1。

Tip

Jcc(条件跳转)指令要检查这3个标志的值,并根据其值决定是否执行某个动作。

<4>EIP指针指令寄存器

保存着CPU要执行的指令地址,由IP寄存器拓展的

EIP是不能直接修改的

程序运行时CPU读EIP中的一条指令的地址,EIP寄存器的值自己增加,CPU每次执行完一条指令,就会通过EIP寄存器读取并执行下一条指令。

第五章 栈

栈内存的作用

暂存函数内的局部变量、调用函数时传递函数参数、保存函数返回后的地址

栈是后进先出的

栈顶指针ESP初始状态指向栈底端

第六章 分析abex’crackme#1

大多数crackme小程序都让我们猜测序列号

如果直接用汇编语言写程序,汇编代码会直接变成反汇编代码

INC值加1
DEC值减1
JMP跳转到指定地址
CMP比较给定的两个操作数*与SUB命令类似,但操作数的值不会改变,仅改变EFLAGS寄存器(若2个操作数的值一致,SUB结果为0,ZF被置为1)
JE条件跳转*若ZF为1就跳转
第七章 栈帧

栈帧:利用EBP寄存器访问栈内局部变量、参数、函数返回地址等手段

调用函数时,先把用作基准点的ESP值保存到EBP,并维持在函数内部。所以是以EBP的值作为基准编写程序的。

在执行完

PUSH EBP

MOV EBP ESP

两条命令后函数main()的栈帧就生成好了(设置好EBP了)

调用某一个函数之前要先使用PUSH把参数a、b压入栈,要清理栈就是让ESP+参数的字节数,就能把它们从栈中清理掉。

Tips

被调函数执行完毕后,函数的调用者Caller负责清理存储在栈中的参数,这被称为cdecl方式

Caller复制清理保存在栈中的参数,这被称为stdcall方式

这些规则统称为调用约定Calling Convention

Return 0的汇编写法可以为XOR EAX,EAX

两个相同的值进行异或运算结果为0

这样写比MOV EAX,0更快,所以常用来初始化寄存器

第八章abex’crackme#2

VB文件的特点 VB文件使用名为MSVBVM60.dll的VB专用引擎

可以编译为本地代码(N code)和伪代码(P code)

VB主要用来编写GUI程序

VB使用的各种信息以结构体的形式保存在文件内部

VC++、VB编译器通常用间接调用的方法,调用ThunRTMain()函数,这个函数在它的专用引擎中

TEST:逻辑比较

与AND一样(仅改变EFLAGS寄存器而不改变操作数的值),若2个操作数中一个为0,则AND运算结果被置为0->ZF=1

TEST AX,AX 是为了检测AX是否为0,这是汇编语法的特征

例子:

TEST AX,AX

JE 403408

If(AX==0)

Goto 403408

JE:条件跳转

若ZF=1,则跳转

第九章 进程管理工具

Process explorer

Sysinternals 上面那个的迷你版

第十章 函数调用约定

函数调用约定:对函数调用时如何传递参数的一种约定。

调用函数前要先把参数压入栈再传递给函数,栈就是定义在进程中的一小段内存空间。进程运行时,栈内存大小才确定。

函数执行完毕后,栈中的参数不必管。因为存在栈里的是临时存的,下一次再用这个栈存东西的时候,会覆盖掉之前的参数。

函数执行完毕后,ESP的值要恢复到函数调用之前。ESP是用来指示栈当前的位置的,栈内存是固定的,所以ESP不恢复初始的话,这个栈就不能用了。

主要函数的约定有如下三种:

优点在于

Cdecl调用者处理栈可以向被调用函数传递长度可变的参数
Stdcall被调用者清理栈被调用者函数内部存在着栈清理代码,使得代码尺寸更小
Fastcall与上类似,不同在于该方式通常会使用寄存器去传参可以实现对函数的快速调用

C语言默认使用Cdecl的方式

Stdcall常用于Win32 API Win32 API虽然是c语言写的库但用的是Stdcall的方式,这可以使C语言之外的其他语言也能直接调用API

第十一章 视频讲座

www.tuts4you.com 的公示板上有40个crackme讲座可供练习

要去除消息框

可以清理栈 但要注意调用rtcMsgBox()函数后返回值要是1(表示确定的按钮)

找到跳出该弹窗的命令 CALL XXXX修改

正确命令如下

ADD ESP,14 14是传递参数的大小

MOV EAX,1

还可以从根头跳过rtcMsgBox()函数 直接改函数开头

PUSH EBP

MOV EBP,ESP

修改成

RETN 4

此处根据要传递的参数大小调整栈 RETN XX

__vbaStrCmp()API 是VB中比较字符串的函数

免责声明:文章转载自《《逆向工程核心原理》笔记第一章到第十一章》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用POI创建word表格合并单元格兼容wpsiOS:quartz2D绘图 (动画)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

认识计算机中的大小端模式

前言 在java中java.nio包下有一个类是ByteOrder,这是什么东东,相信有很多人不知道。在我看了关于java.nio中有本书中就介绍到了。我努力的回忆我大学课本中学到过吗,好像没有。这是计算机理论方面的知识了。百度百科中就有关于“大小端模式的介绍”。猛击这里吧 大小端模式的定义 大端模式,是指数据的高位,保存在内存的低地址中,而数据的低位,保...

C# 模拟鼠标(mouse_event)

想必有很多人在项目开发中可能遇见需要做模拟鼠标点击的小功能,很多人会在 百度过后采用mouse_event这个函数,不过我并不想讨论如何去使用mouse_event 函数怎么去使用,因为那没有多大意义。 [csharp] view plaincopy static void mouse_event(int dwFlags, int ...

iOS 强制退出程序APP代码

1、先po代码 // 退出程序 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 UIAlertView* alert = [[UIAlertView alloc] initWithTitle:self.exitapplica...

异常:Unknown lifecycle phase "mvn". You must specify a valid lifecycle

这是在使用maven打包方式启动springboot项目时出现的异常, 我的异常原因属于下面的情况: 此时maven指令行为:mvn spring-boot:run. 如果写成这样会导致最终的maven指令为:mvn mvn spring-boot:run. 所以需要注意修改为:spring-boot:run即可. 还有一种可能,Maven插件[Run A...

通过经纬度获取地址信息

摘要 Google Maps API Web Services,是一个为您的地图应用程序提供地理数据的 Google 服务的 HTTP 接口集合。具体包括:Google Geocoding API、Google Directions API、Google Elevation API、Google Places API。本文将探讨如何通过Google Ge...

Golang中的插件开发

  插件化开发提供了很多便利,可动态扩展程序的相关功能,如Windows中的DLL、Linux中的So文件、还有IDEA中的插件,应用范围不可谓不广;   在Golang中提供了自己的插件机制,可使用其进行插件化开发;在Golang的plugin包中提供了加载插件、调用插件中函数的相关方法; Golang中的插件机制使用非常简单;就只有这么三步:   1、...