封包的加密与解密、线程发包、收包

  • 2026-01-24 17:13:12

三大发包函数

send

WSASend

sendto

模块前缀为ws2_32

WSPSend (在同一个电脑上位置是固定的)

DXF单机版 私服

找到WSPSend

附加上口袋西游(或者任何的send发包的软件都可以),跳到send位置

send 第三个call下断(win7是第三个,win10是第四个),断下后F7进入,这就是WSPSend的位置。

附加到目标进程,跳转到这个地址,下断。

有时WSASend胡乱断,不是真正的发包 ,根据它的特征码,去搜索。查找–>所有命令 ,输入特征码,然后右键–>在每个命令上下设置断点。然后在所有被断下的位置做标记(注释),并取消断点。然后去执行喊话等发包操作,看在哪断下。如果不断,说明在刚才被标记的里面。之后逐一下断测试。

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

32

graph

z([找出三大发包函数])-->

可直接找出

z-->

不可直接找出 -->

找出WSPSend-->

附加其它游戏-->

跳到send处-->

z1["在第三/四个call下断
(win7 第三个,win10 第四个)"]-->

断下后F7进入-->

此处就是WSPSend的位置-->

z2["记录下来,附加到目标进程,
跳转到这个地址,下断"]-->

正常断-->

找到发包函数

z2-->胡乱断-->

记录它的特征码-->

查找所有命令-->

输入特征码-->

右键在每个命令上下设置断点-->

在所有被断下的位置做注释-->

取消断点-->

执行喊话等发包操作-->

看在哪断下-->

如果不断-->

说明在刚才注释的里面-->

逐一下断测试

找出WSPSend -->

在三大发包函数下-->

找到ws2_32.WEP-->

再下一句就是WSPSend的外部-->

下断后反复操作游戏-->

断下后F7进入

线程发包

线程发包的特点:

断得非常频繁

任何功能堆栈返回都是一样的

1

2

3

4

5

6

7

graph

y0(["判断是不是线程发包"])-->

观察断得是否频繁-->

y1["在发包函数头部下断,
喊话断一次,
按K打开堆栈,
复制整个表"]-->

y2["走路断一次,再复制整个表"]-->

y3{"对比两次的表内容是否相同"}-->|相同|线程发包

y3-->|不同|普通发包

正常流程

找到发包函数

判断是不是线程发包

判断包内容(非包长)的地址是否变化

跳出线程发包的步骤:

1

2

3

4

5

6

7

8

9

10

11

graph

z([跳出线程发包])-->z2{"判断包内容
(非包长)的地址
是否变化"}

z2 --是--> z4[唯一突破口,找到包的内容来源]--> z5["向上追,直到追到不变的地址"]---> z7["在不变的地址上,
下硬件写入断点,
返回,看是否跳出线程外"]

z2 --否--> z6[在包内容处下硬件写入dword断点] --> 就能跳出线程发包 --> z8

z7 -.->|否| z5

z7 --是--> z8([yeah])

z7-.->z9["从线程发包处,向外层层标注"]

z8-.->z10(["此时可以来验证功能函数"])-.->

z11["下断并喊话,反复ctrl+f9多次,并标记"]-->

z12(["逐一测试标记call并验证"])

条件断

实例

1

2

3

4

5

6

7

8

9

[[esp+8]]!=11&&[[esp+8]]!=4

# esp 是堆顶

# == 等于

# != 不等于

# && 和

word ptr[[[ebp+8]+4]] != 11

#word ptr 代表一个字节

找出加密封包

找出加密封包的步骤:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

graph

z["跳出线程发包后"]

z1["配好表达式"]

z2["验证是不是加密封包"]

z3["在此处(跳出线程封包的位置)下断"]

z3a["喊话或者其它动作,令其断下"]

z4["dd 表达式"]

z5["在send处下断"]

z5a["喊话或者其它动作,令其断下"]

z6["找到封包内容"]

z7["此处应该就是封包内容"]

z8{"对比"}

z9["确定是加密封包"]

z10["失败,寻找错误或者换其他方法"]

z-->z1-->z2

z2-->z5-->z5a-->z6-->z8

z2-->z3-->z3a-->z4-->z7-->z8

z8--相同-->z9

z8--不相同-->z10

明文包

1

2

graph LR

功能call --> 明文封包 --> 加密CALL --> 加密封包

到加密封包的外层找明文包。

找出明文封包的步骤:

1

2

graph LR

加密封包 --> Ctrl+F9到外层找明文包

找出加密CALL

找出加密CALL的步骤:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

graph

z1["找出已加密的最外层"]-->

z2["找出明文封包"]-->

z3["进入明文包"]-->

z4["先走一圈,并标注跳转"]

z5["回到明文封包外部"]-->

z6["下断"]-->

z7["喊话"]-->

z8["dd 明文封包内容"]-->

z9["F7进入明文封包"]-->

z10["F8逐步走,并观察内存窗口中明文封包何时变化"]-->

z11["如果经过某个call之后,内存窗口内容变化"]-->

z12["找到加密CALL"]-->

z13(["覆盖式加密"])

z10-->没有变化-->

x1(["复制式加密"])-->|没遇到过|需要从明文包开始逐步分析-->

看到底哪里利用过包地址或者包内容

分析加密CALL

需要分析的元素:

CALL的参数

包长

包地址

加密地址

加密长度

密钥(找到就行)

CALL内的寄存器

调用加密CALL加密

实例

1

2

3

4

5

6

7

8

9

10

11

12

push 12345678

push 12345678

push 11

mov ecx,[00f84ba4]

mov ecx,[ecx]

mov ecx.[ecx+4]

mov ecx,[ecx+14]

mov ecx, [ecx]

lea ecx,[ecx+54]

push ecx

call 00B94700

add esp, 10

发送喊话函数封包

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

void HXSYDialog::OnBnClickedEutton15()

{

byte a[100] = {0x11,0x00,0x7E,0x00,0x00,0x00,0x00,0x02,0x00,0x31,0x31, OFF, OxFF,OxFF,OxFF,0x00,0x00,0x00,0x00,0x60,0xA8,0x6C}:

DWORD 包长 = 0x13;

DWORD 包地址=(DWORD)a;

DWORD 加密地址 = 包地址+2;

DWORD 加密长度 = 包长-2;

__asm

{

push 加密地址

push 加密地址

push 加密长度

mov ecx, 0x00f84ba4

mov ecx, [ecx]

mov ecx, [ecx]

mov ecx, [ecx+0x4]

mov ecx, [ecx+0x14]

mov ecx, [ecx]

lea ecx, [ecx+0x54]

push ecx

mov eax, 0x00B94700

call eax

add esp, 0x10

}

HWND 窗口句柄=FindWindowA("Lapis Network C1ass",0);

DWORD A=GetWindowLongW(窗口句柄,-21);

DWORD S=*(DWORD*)(A+0x38);

send(S,(const char*)包地址,包长,0);

//TODO:在此添加控件通知处理程序代码

}

C++写 加密CALL

1

2

3

4

5

6

7

8

__declspec(naked) void 加密Ca11(DWORD秘钥,DWORD 加密长度,DWOED 加密地址,DWORD 加密地址2)

{

__asm

{

...

}

}

//__declspec(naked) 裸体函数

结合加密call,写加密封包,完全不走游戏代码

不走游戏代码,写吃药封包

收包recv

recv也存在重写问题

1

2

3

4

5

6

7

8

9

10

graph LR

subgraph 收包正常流程

z1["recv"]

z2["明文收包"]

z3["加密"]

z4["解密"]

z5["反复MemoryCopy"]

z6["写入内存"]

end

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

1

2

3

4

5

6

7

8

9

graph LR

z1["recv下断"]

z3["正常操作"]

z4["寻找明文收包"]

z5["recv被重写"]

z6["双开喊话"]

z1-->|可断|z3

z1-->|不可断|z5-->z4-->z6-->A喊-->B搜索-->反复验证并最终确定-->向上层返回-->直到找到明文收包

控件包

1

2

3

4

5

6

7

graph

在明文包处-->

|下条件断 过滤心跳包|通过会触发向服务器发包的功能按键-->

z1["触发执行断点"]-->

堆栈 & K键堆栈 & z2["外层(推荐)"]

z2-->

逐层验证并确定