目录

OD常识及技巧

菜单栏

E 模块

T 线程(挂起与激活)resume恢复线程

B 执行断点

HBP 硬件断点

OD指令

dd 查看dword

db 查看字节集

hw 硬件写入断点

hr 硬件访问断点

快捷键

CTRL + A 分析代码

CTRL + S 查找命令序列

F2 下断和取消

Shift+F2 条件断点

F4 代码执行一次

F7 单步步入(进call)

F8 单步步过(不进call)

条件断点

== 等于

!= 不等于

&& 和

|| 或

汇编指令

mov 赋值

lea 传址

push 入栈

pop 出栈

add 加

sub 减

mul 乘法

div 除法

call 函数

retn 返回

rep 主要用来重复执行指令 详见 REP指令前缀簇

​ 指令:REP MOVS mem8/16/32, m8/16/32

​ 描述:从DS:[(E)SI]中复制(E)CX个字节/字/双字到ES:[(E)DI]

DS:[(E)SI]由于(E)SI寄存器中保存的是源操作数的地址,所以DS:[(E)SI]指的就是该地址保存的值

1
2
3
4
5
mov ecx,12
rep movs dword ptr es:[edi],dword ptr [esi]
# 从[esi]中复制 ecx个四字节 到ES:[edi]
# 每复制一次 esi 和 edi 的地址要加4,而ecx减1
# 源自 飞郁网络培训 2018-2019 52第二部分第八节结构体数组 55结构体数组实例1

断点

内存访问 断在执行之前

内存写入 断在执行之前

硬件访问(CE) 断在执行之后

硬件写入(CE) 断在执行之后

硬件执行 可添加条件断点

OD断点缺点

一次只能断在一个位置

CE则可以把所有相关断点列在一起

OD断点优点

高亮插件,易于追踪

堆栈

esp 栈顶指针 堆栈顶端的刻度

ebp 栈底指针 本层函数的栈底

ebp 不稳定,有时不是栈底,而是普通寄存器

判断方法,看ebp与esp的差距是否很大

如果差距大,则是普通寄存器

堆栈平衡

特性

  • esp 不能变化

寄存器

EAX call的返回值

ECX call的参数

找call总结

找call时,需要注意的地方:

  1. 找call在send上下断,尽量避免被心跳call干扰

  2. 在我们找call的时候,会有一些其它伴生函数干扰

    例如

    1. 打怪、打开npc对话框或者寻路call,可能会先触发走路call
    2. 打坐、释放技能可能会伴随快捷键函数

找到call后,我们还需要对函数的参数、寄存器进行分析。

  1. 外平栈,看清楚参数的数量,是否和平栈的数值对应。在调用call的时候一定要平栈,否则会崩溃。
  2. 内平栈,通过retn的数值,来判断参数的数量,并且分析ecx的来源。个别情况下,还需要分析edx和esi等参数的来源。
  3. 有些函数调用的是虚函数,比如 call eax或者call [edx+8],我们需要去分析call里寄存器的来源。
  4. 如果我们的参数中需要用到eax,但是eax无法很快的得到结果,这时可以通过调用eax来源的call来获得,前提是分析清楚来源函数的参数和寄存器。调用连call。

带有结构体的函数

  1. 申请一片内存(可以通过OD插件)
  2. 在内存中填写结构体里的内容
  3. 将我们申请的内存地址,push到call中
  4. 进行调用

无法通过发包函数获得的call

例如:寻路,控件,按键

1
2
graph LR
寻路-->走路-->z["通过目的地坐标,<br>下写入断点"]
1
2
graph LR
控件-->z["可以通过背包的打开状态,<br>来对状态下写入断点"]
1
2
3
4
5
graph LR
按键 -->z & z1 & z2
z["可以通过背包的打开状态,<br>来对状态下写入断点"]
z1["鼠标点击"]
z2["键盘"]

发包函数

  1. bp send
  2. send sendto WSASend
  3. 重新实现的发包函数 WSPSend
  4. 线程发包
1
2
3
4
5
6
graph 
subgraph 普通发包
喊话call --> 喊话_内层call --> 组包的过程1  --> 最内层喊话call-->|进call后的头部<br>就是<br>最外层明文包头部<br>往下走就是|明文封包 --> 加密 --> 发包发送
走路call --> 走路_内层call --> 组包的过程2  --> 最内层走路call-->|进call后的头部<br>就是<br>最外层明文包头部<br>往下走就是|明文封包
其它call --> 其它_内层call --> 组包的过程3  --> 最内层其它call-->|进call后的头部<br>就是<br>最外层明文包头部<br>往下走就是|明文封包
end

控件

控件输入

寻找突破口:

1
2
3
4
5
6
7
8
9
graph
z1["方法一"] 
z2["方法二"]
z3["字符串的长度"]
z4["直接搜索字符串"]
z5["下写入断点"]

z1-->z3-->z5
z2-->z4-->z5

控件点击

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
graph
z["下写入断点"]
z1["方法一"] 
z2["控件界面打开,搜1或0"]
z3["控件界面关闭,搜0或1"]
z4["方法二"]
z5["单选框选中,搜1或0"]
z6["单选框未选中,搜0或1"]

z1-->z2-->z3-->z
z4-->z5-->z6-->z

按键call

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
graph
z["按一下对应按键来触发"]
z1["方法一"] 
z2["通过按键触发发包函数"]
z3["在发包函数处下断"]
z4["方法二"]
z5["比如通过背包打开<br>或者关闭的标志位<br>来进行查找"]
z6["下写入断点"]
z7["之后返回,<br>就有可能断在按键call"]
z8["有可能断在按键call"]
z9["proc断点"]
z10["方法三"]

z1-->z2-->z3-->z7
z4-->z5-->z6-->z-->z8
z10-->z9

proc断点 (源自 飞郁网络培训 2018-2019 2018.12.22 proc断点分析按键CALL)

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/%E6%88%AA%E5%B1%8F2021-10-07%20%E4%B8%8B%E5%8D%887.53.23.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/image-20211007195445271.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/image-20211007195523875.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/image-20211007195611161.png

插件

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/%E6%88%AA%E5%B1%8F2021-10-07%20%E4%B8%8B%E5%8D%887.35.59.png

IDA

用于查看伪函数代码

对于复杂的结构体、数组、二叉树、链表,更直观。

跳出VM

1
2
3
4
5
graph
z1([遇到VM])
z2[追附近地址<br>最好是对象]
z3[需要自己算偏移]
z1-->z2-->z3