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


    第一章/第二章 分析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 to Ctrl+G 移动到指定地址,用来查看代码或者内存,运行时不能用
    Execute till Cursor F4 执行到光标位置,即直接转到要调试的地址
    Comment ; 添加注释
    User-defined commet 右键菜单Search for User-defined comment
    Label : 添加标签
    User-defined label 右键菜单Search for User-defined label
    Set/Reset BreakPoint F2 设置或取消断点(BP)(BP就是断点
    Run F9 运行(若设置了断点,则执行至断点处)
    Show the current EIP * 显示当前EIP(命令指针)位置
    Show the previous Cursor - 显示上一个光标的位置
    Preview CALL/JMP address Enter 若光标处有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 code CPU指令
    PE windows可执行文件(EXE、DLL、SYS等)

    第三章 小端序标记法

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

    BYTE b= 0x12
    WOED w= 0x1234
    DWORO dw= 0x12345678
    char str[]= “abcde”

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

    TYPE NAME SIZE 大端序类型 小端序类型
    BYTE b 1 [12] [12]
    WOED w 2 [12][34] [34][12]
    DWORD dw 4 [12][34][56][78] [78][56][34][12]
    char[] str 6 [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-bit 32-bit
    AH AL AX EAX 累加器(针对操作数和结果数据)
    BH BL BX EBX 基址寄存器(DS段中的数据指针)
    CH CL CX ECX 计数器(字符串和循环操作)
    DH DL DX EDX 数据寄存器(I/O指针)
    BP EBP 拓展基址指针寄存器(SS段中栈内数据指针)
    SI ESI 源变址寄存器(字符串操作源指针)
    DI EDI 目的变址寄存器(字符串操作目标指针)
    SP ESP 栈指针寄存器(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中比较字符串的函数

  • 相关阅读:
    Postman请求Https接口与认证
    HTML实用
    ORM实例教程_转
    web跨域问题CORS
    gin入门
    swagger应用
    k8s之容器
    腾讯高级工程师:如何从头开始写游戏服务器框架_转
    tensorflow入门
    sublime Text 3实用功能和常用快捷键收集
  • 原文地址:https://www.cnblogs.com/Nickyl07/p/13761872.html
Copyright © 2020-2023  润新知