逆向问题记录

来源:互联网 发布:自动算账软件 编辑:程序博客网 时间:2024/06/05 16:49
  1. 无法区分编译器自动生成的代码和自己编写的代码

解决:

  1. 源码对比法

    写对应编译器的 demo 程序与分析的程序进行对比分析

    之后再使用 OD 动态调试或是 IDA 静态分析

    总结出一些库或者 CALL 的特征,方便下段

  2. API 下断栈回溯跟踪法

    根据栈回溯分析关键跳

    而分析具体的算法,需要耐心,

    分析上下文当中的每一个 CALL 的参数和返回值信息

    以及一些敏感的内存写入或是访问代码

    1. IDA 的 F5 命令,反编译成 C 代码之后如何修改?

解决:

  1. 先为函数命名,根据其功能

    1. 还有参数、局部变量

    2. IDA 快捷键

export 窗口 双击 start 或者其他导出函数,跳转到反汇编窗口

切换视图 单击空格

切换窗口 单击选项卡

窗口关闭再次打开 菜单 - View-OpenSubView - 对应的窗口

窗口不小心拽出 关闭活动窗口,再在菜单中打开

  1. 换算随机基址

假设 OD 中 OEP 地址:0138F5CD IDA 中 OEP 地址 :0042F5CD

 计算在 IDA 中的地址

公式:OD 中 OEP 地址 - OD 中的映像基址 + 原始映像基址

OD 中的映像基址如何查看?

  1. 点击工具栏 E 枚举当前所有模块,找到主模块,主模块是 01360000

根据公式,在 IDA 中的地址 = 0138F5CD-01360000+00400000=42F5CD

IDA 中 OEP 地址:0042F5CD

  1. exe 的默认映像基址是多少?DLL 的默认映像基址是多少?

    exe:00400000

    dll: 10000000

题目假设一

DLL 随机基址之后的一个代码地址 01520330,随机基址是 01000000

问,在 IDA 中的地址是多少?

01520330-01000000+10000000=10520330

实例分析,main 函数

1. 反编译查看代码,看是否能看懂,不能看懂,返回反汇编窗口老老实实的分析汇编

2. 先给函数起个名字,然后老老实实从开始分析汇编

3. 根据汇编代码,猜测代码是数组赋值

那么,在局部变量 var_3C 上双击到栈窗口,对局部变量重定义

选中以下代码

点击右键,选择 Arrary,定义局部变量为数组

点击 OK 即可, 需要注意的是,数组设置的窗口,有对数组大小的设定,可以修改

最好是再给变量根据含义重新命名

回到反汇编窗口继续分析,又发现一个数组,从 var_32 到 var_E, 同样方式重定义为数组

重新定义为数组之后,代码显示

继续分析,根据 buf 的引用,重命名 (ebp-78h 就是 szBuf)

继续分析,发现一个 for 循环

继续分析,根据参数可知 Printf 和 Scanf 功能

Call sub_42fdc5 这个函数不确定,动态调试分析

发现选中的代码,成功获取到了缓冲区信息

继续一点一点分析

小技巧

  1. 当出现重命名无法修改的时候

先备份一份 IDB 文件,然后在需要修改的代码处,

U 一下,重定义当前代码,然后再 C,创建代码

  1. scanf_s 遇到空格之后会停止接收 (需要加 %[]…),但是接收缓冲区中有数据的

接收缓冲区的地址是 _iob_func 函数的返回地址 + 8。

_iob_func

  1. 虚函数的调用方式以及汇编代码形式

Mov eax,[ecx] // 取虚函数表指针 (vptr)

Mov eax,[eax] // 取虚函数表中的第一个虚函数

Call eax // 调用虚函数

Mov eax,[ecx] // 取虚函数表指针 (vptr)

Call [eax+0x20] // 调用虚函数

实例分析

MFC 中的 OnInitDialog, 由于它是虚函数,所以应该也是类似调用 (call eax。。。)

  1. 在 OnInitDialog 中添加::MessageBoxA(0,0,0,0);, 编译

  2. 使用 OD 调试 MFC 程序

  3. 在让程序跑起来,由于 OnInitDialog 函数是在显示对话框之前调用的,程序跑起来信息框会先弹出来,我们在 MessageBoxA 的返回处下断

  4. 断下之后,返回地址跟随或者跟踪到上一层函数,这一层函数就是 OnInitDialog

  5. 再上一层的调用方式应该就是虚函数调用

动态库

静态库

  1. 虚函数调用的代码是 MFC 的代码,非用户编写的代码

一般来说都是有特征的

(1) 汇编代码特征:

je short013C60A2

mov ecx,dword ptr ss:[ebp-0x4]

mov edx,dword ptr ds:[ecx]

mov esi,esp

mov ecx,dword ptr ss:[ebp-0x4]

mov eax,dword ptr ds:[edx+0x17C]

call eax

cmp esi,esp

(2) 二进制特征

74??8B4DFC8B118BF48B4DFC8B827C010000FFD03BF4

OnInitDialog 的特征

第一个 CALL 调用的是 CDialog 中的 OnInitDialog,有以下类似字符串

方法 2:通过功能 API 下断

User32.EnableWindow 可以将按钮置为无效

方法 3:通过资源修改(思路,有时不成功)

MFC 按钮的特征

  1. 自己建一个工程,拖动一个按钮上去,处理一下点击事件,弹出一个 MessageBoxA

  2. 分析程序,提取特征

Debug

FF 55 F8 CALL DWORD PTRSS:[EBP-8]

Release

FF 55 14 CALL DWORD PTRSS:[EBP+14]

分析 MFC 按钮事件

  1. 根据特征下所有代码上下断点

  2. 重新加载程序,断下来的全部去掉

  3. 然后再点击按钮

分析具体的 CALL 内的代码

两个 CALL 一样,且参数 1 个是 true ,1 个是 false,

且 CALL 内是 IsWindow,是个 mfc 函数

 可推测是 UpdateData

push 0x1

mov ecx,[local.2]

call

mov eax,[local.2] ; this 指针

mov ecx,dword ptr ds:[eax+0xC0] ; 获取成员变量

add ecx,0x1 ; 累加

mov edx,[local.2]

mov dword ptr ds:[edx+0xC0],ecx ; 更新成员变量

mov ecx,[local.2]

call 0147E3D4 ; 调用成员函数

push 0x0

mov ecx,[local.2]

call

mov [local.2],ecx ; this 指针

mov eax,[local.2] ; this 指针

cmp dword ptr ds:[eax+0xC0],0xC ; 判断成员变量

jnz short 0149BF9D

mov eax,[local.2]

cmp dword ptr ds:[eax+0xC4],0x8 ; 判断成员变量

jnz short 0149BF9D

mov eax,[local.2]

83B8 C8000000>cmp dword ptr ds:[eax+0xC8],0x5 ; 判断成员变量

jnz short 0149BF9D

push 0x1

push 0x3E8

mov ecx,[local.2]

call ; 让按钮亮起来

小技巧

如何取特征

  1. Shift+x 复制 二进制代码(快捷键是 StrongOD 提供的)

  2. 在目标程序中代码段使用 Ctrl+B,右键复制到二进制窗口,查找对应特征代码

  3. Ctrl+L 多次查找,如果特征不唯一,则需要优化特征

查找命令

  1. 在反汇编窗口右键查找所有命令

  2. 会搜索到模块中所有类似的汇编指令

  3. 右键在每个命名上设置断点,调试分析

查找命名序列(Ctrl+S)

010Editor

  1. 安装之后,打开软件,菜单 - tool-register 注册软件

  2. 随机输入用户名和序列号,会弹出窗口

窗口的 API:

(1) CreateWindowExA

(2) CreateWindowExW

(3) CreateDialogIndirectParamA

(4) CreateDialogIndirectParamAorW

(5) CreateDialogIndirectParamW

(6) CreateDialogParamA

(7) CreateDialogParamW

(8) CreateMDIWindowA

(9) CreateMDIWindowW

(10) DialogBoxIndirectParamA

(11) DialogBoxIndirectParamAorW

(12) DialogBoxIndirectParamW

(13) DialogBoxParamA

(14) DialogBoxParamW

(15) MessageBoxA

(16) MessageBoxExA

(17) MessageBoxExW

(18) MessageBoxIndirectA

(19) MessageBoxIndirectW

(20) MessageBoxTimeoutA

(21) MessageBoxTimeoutW

(22) MessageBoxW

分析步骤

  1. 根据弹出对话框,猜测 API,在我们熟悉的 API 上下断

先在主模块入手,Ctrl+N 查看当前模块函数信息

如果主模块没有引入我们想要的窗口函数,那么再分析其他 UI 模块

  1. UI 模块根据名称来确定

本程序使用的是 qt4 有模块 QtGui4.dll

(因为还有 MSVCR90.dll,所以本程序应该是 VS2008 编译的)

  1. 在 QtGui4.dll 模块中 Ctrl+N 查看当前模块函数

找对应的窗口 API 下断

CreateWindowExW

  1. 运行程序,点击注册按钮,看是否断下,如果没有断下,继续找其他窗口 API

本程序,已经断下,所以不用再找了

  1. 当断下之后,栈回朔,分析堆栈信息

  2. 分析调用情况 (k 窗口、以及堆栈窗口)

  3. 分析字符串,即输入的字符信息(堆栈窗口)

以下是堆栈信息

我们只需分析主模块 010Editor 的调用即可

每一个调用,都需要双击进去看一下,有无敏感字符串

Ctrl+A 分析模块,可以找到上一层的调用

根据字符串找关键跳

关于网络程序的分析

  1. socket api

Ws2_32.dll

  • socket connect

  • WSAStartup

  • send sendto WSASend WSASendTo

  • recv recvfrom WSARecvWSARecvFrom

wininet.dll

winhttp.dll

  1. 分析网络程序思路

在 socket api 上下断点栈回朔,分析堆栈以及对应的 CALL 参数

如果加密,找到未加密的传参 CALL,如果未加密,直接分析传参的 CALL

注意:分析网络程序的协议重在分析数据

  分析数据的由来

在 send 下断点,看参数,找参数中的数据缓冲区,是如何填充的

以及是什么意思,每一个网络请求都需要一点一点分析

原创粉丝点击