首页
论坛
课程
招聘
[原创]WOW怀旧 发包函数分析 并 HOOK
2021-5-6 16:49 6582

[原创]WOW怀旧 发包函数分析 并 HOOK

2021-5-6 16:49
6582

WOW怀旧服 明文发包获取 和 HOOK

0.前言

只用于学习 不要用于任何非法 如果哪里有不对的地方 请提出来 本人也是刚开始接触 多多和大佬们学习学习

1. 找出什么通过什么函数发包 send sendto WSASend

可以看到在send下段断下 其余不断

2. 判断是否为线程发包

通过不同动作 下段查看堆栈是否相同

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
33
34
35
36
37
38
39
40
41
喊话 断下
地址               返回到              返回自              大小   注释                          方  
000000000012D808 000000014160FF9D 000007FEFF348000 C0   ws2_32.000007FEFF348000     用户模块
000000000012D8C8 0000000141610394 000000014160FF9D 50   wowclassic.000000014160FF9D 用户模块
000000000012D918 0000000141627E5F 0000000141610394 140  wowclassic.0000000141610394 用户模块
000000000012DA58 0000000141610759 0000000141627E5F 30   wowclassic.0000000141627E5F 用户模块
000000000012DA88 0000000140A3561B 0000000141610759 90   wowclassic.0000000141610759 用户模块
000000000012DB18 0000000140A356E0 0000000140A3561B 50   wowclassic.0000000140A3561B 用户模块
000000000012DB68 0000000140F4EF7E 0000000140A356E0 510  wowclassic.0000000140A356E0 用户模块
 
000000000012E078 0000000140F3147B 0000000140F4EF7E 1100 wowclassic.0000000140F4EF7E 用户模块
000000000012F178 0000000141996779 0000000140F3147B 40   wowclassic.0000000140F3147B 用户模块
000000000012F1B8 000000014199A063 0000000141996779 130  wowclassic.0000000141996779 用户模块
000000000012F2E8 00000001419960AF 000000014199A063 40   wowclassic.000000014199A063 用户模块
000000000012F328 0000000141989707 00000001419960AF 30   wowclassic.00000001419960AF 用户模块
000000000012F358 0000000141996D03 0000000141989707 150  wowclassic.0000000141989707 用户模块
000000000012F4A8 000000014199627E 0000000141996D03 50   wowclassic.0000000141996D03 用户模块
000000000012F4F8 000000014198AB74 000000014199627E 50   wowclassic.000000014199627E 用户模块
000000000012F548 00000001403A8E6C 000000014198AB74 70   wowclassic.000000014198AB74 用户模块
000000000012F5B8 00000001402ED8C2 00000001403A8E6C 60   wowclassic.00000001403A8E6C 用户模块
000000000012F618 0000000141CD873E 00000001402ED8C2 70   wowclassic.00000001402ED8C2 用户模块
000000000012F688 00000001402E8763 0000000141CD873E F0   wowclassic.0000000141CD873E 用户模块
000000000012F778 00000001402C3C06 00000001402E8763 60   wowclassic.00000001402E8763 用户模块
000000000012F7D8 00000001402C3677 00000001402C3C06 90   wowclassic.00000001402C3C06 用户模块
000000000012F868 0000000140A3E840 00000001402C3677 40   wowclassic.00000001402C3677 用户模块
000000000012F8A8 0000000140A3E3F5 0000000140A3E840 50   wowclassic.0000000140A3E840 用户模块
000000000012F8F8 0000000140A3F79A 0000000140A3E3F5 C0   wowclassic.0000000140A3E3F5 用户模块
000000000012F9B8 0000000140A3F16F 0000000140A3F79A 30   wowclassic.0000000140A3F79A 用户模块
000000000012F9E8 000000014046E7FA 0000000140A3F16F 200  wowclassic.0000000140A3F16F 用户模块
000000000012FBE8 0000000077569BD1 000000014046E7FA C0   wowclassic.000000014046E7FA 系统模块
000000000012FCA8 00000000775698DA 0000000077569BD1 80   user32.0000000077569BD1     系统模块
000000000012FD28 0000000140A3E9F5 00000000775698DA C0   user32.00000000775698DA     用户模块
000000000012FDE8 00000001402C2C83 0000000140A3E9F5 50   wowclassic.0000000140A3E9F5 用户模块
000000000012FE38 00000001402C26DC 00000001402C2C83 30   wowclassic.00000001402C2C83 用户模块
000000000012FE68 000000014019C9AA 00000001402C26DC 50   wowclassic.00000001402C26DC 用户模块
000000000012FEB8 00000001401AD6FA 000000014019C9AA 30   wowclassic.000000014019C9AA 用户模块
000000000012FEE8 00000001401AD71B 00000001401AD6FA 30   wowclassic.00000001401AD6FA 用户模块
000000000012FF18 0000000141AD69D6 00000001401AD71B 40   wowclassic.00000001401AD71B 用户模块
000000000012FF58 000000007744652D 0000000141AD69D6 30   wowclassic.0000000141AD69D6 系统模块
000000000012FF88 000000007767C521 000000007744652D 50   kernel32.000000007744652D   系统模块
000000000012FFD8 0000000000000000 000000007767C521      ntdll.000000007767C521      用户模块
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
33
34
35
36
37
38
39
40
41
42
43
44
点击登录触发
地址               返回到              返回自              大小  注释                          方  
000000000012ED18 000000014160FF9D 000007FEFE438000 C0  ws2_32.000007FEFE438000     用户模块
000000000012EDD8 0000000141610394 000000014160FF9D 50  wowclassic.000000014160FF9D 用户模块
000000000012EE28 0000000141627E5F 0000000141610394 140 wowclassic.0000000141610394 用户模块
000000000012EF68 0000000141610759 0000000141627E5F 30  wowclassic.0000000141627E5F 用户模块
000000000012EF98 0000000140A3561B 0000000141610759 90  wowclassic.0000000141610759 用户模块
000000000012F028 0000000140A356E0 0000000140A3561B 50  wowclassic.0000000140A3561B 用户模块
000000000012F078 00000001401A54C6 0000000140A356E0 70  wowclassic.0000000140A356E0 用户模块
 
000000000012F0E8 0000000140405CDF 00000001401A54C6 90  wowclassic.00000001401A54C6 用户模块
000000000012F178 000000014042DD2E 0000000140405CDF 30  wowclassic.0000000140405CDF 用户模块
000000000012F1A8 0000000141996779 000000014042DD2E 40  wowclassic.000000014042DD2E 用户模块
000000000012F1E8 000000014199A063 0000000141996779 130 wowclassic.0000000141996779 用户模块
000000000012F318 00000001419960AF 000000014199A063 40  wowclassic.000000014199A063 用户模块
000000000012F358 0000000141989707 00000001419960AF 30  wowclassic.00000001419960AF 用户模块
000000000012F388 0000000141996D03 0000000141989707 150 wowclassic.0000000141989707 用户模块
000000000012F4D8 000000014199627E 0000000141996D03 50  wowclassic.0000000141996D03 用户模块
000000000012F528 000000014198AB74 000000014199627E 50  wowclassic.000000014199627E 用户模块
000000000012F578 00000001403A8E6C 000000014198AB74 70  wowclassic.000000014198AB74 用户模块
000000000012F5E8 0000000141CCE456 00000001403A8E6C 60  wowclassic.00000001403A8E6C 用户模块
000000000012F648 0000000141CCF1B8 0000000141CCE456 30  wowclassic.0000000141CCE456 用户模块
000000000012F678 0000000141CCF743 0000000141CCF1B8 30  wowclassic.0000000141CCF1B8 用户模块
000000000012F6A8 00000001402E93A4 0000000141CCF743 80  wowclassic.0000000141CCF743 用户模块
000000000012F728 00000001402C3C06 00000001402E93A4 60  wowclassic.00000001402E93A4 用户模块
000000000012F788 00000001402C33CA 00000001402C3C06 60  wowclassic.00000001402C3C06 用户模块
000000000012F7E8 00000001402C38AB 00000001402C33CA 90  wowclassic.00000001402C33CA 用户模块
000000000012F878 0000000140A3E840 00000001402C38AB 40  wowclassic.00000001402C38AB 用户模块
000000000012F8B8 0000000140A3DF97 0000000140A3E840 40  wowclassic.0000000140A3E840 用户模块
000000000012F8F8 0000000140A3FB07 0000000140A3DF97 C0  wowclassic.0000000140A3DF97 用户模块
000000000012F9B8 0000000140A3F16F 0000000140A3FB07 30  wowclassic.0000000140A3FB07 用户模块
000000000012F9E8 000000014046E7FA 0000000140A3F16F 200 wowclassic.0000000140A3F16F 用户模块
000000000012FBE8 0000000076F39BD1 000000014046E7FA C0  wowclassic.000000014046E7FA 系统模块
000000000012FCA8 0000000076F398DA 0000000076F39BD1 80  user32.0000000076F39BD1     系统模块
000000000012FD28 0000000140A3E9F5 0000000076F398DA C0  user32.0000000076F398DA     用户模块
000000000012FDE8 00000001402C2C83 0000000140A3E9F5 50  wowclassic.0000000140A3E9F5 用户模块
000000000012FE38 00000001402C26DC 00000001402C2C83 30  wowclassic.00000001402C2C83 用户模块
000000000012FE68 000000014019C9AA 00000001402C26DC 50  wowclassic.00000001402C26DC 用户模块
000000000012FEB8 00000001401AD6FA 000000014019C9AA 30  wowclassic.000000014019C9AA 用户模块
000000000012FEE8 00000001401AD71B 00000001401AD6FA 30  wowclassic.00000001401AD6FA 用户模块
000000000012FF18 0000000141AD69D6 00000001401AD71B 40  wowclassic.00000001401AD71B 用户模块
000000000012FF58 000000007703652D 0000000141AD69D6 30  wowclassic.0000000141AD69D6 系统模块
000000000012FF88 000000007716C521 000000007703652D 50  kernel32.000000007703652D   系统模块
000000000012FFD8 0000000000000000 000000007716C521     ntdll.000000007716C521      用户模块

我们可以看出明显不是线程发包 140A356E0应该是最外层的发包函数

 

image-20210506160721571

 

这两个应该是最内层的功能函数 我们拿过来 去X64DBG看看

 

image-20210506160840304

 

发现什么都不断 只有喊话断下

 

image-20210506160908820

 

这里也可以看出 内存里面存放的使我们喊话的内容

 

进去这个CALL 看看 应该就是我们的通用CALL了

1
2
3
4
5
6
7
0000000141636FC0 | 48:8BD1                  | mov rdx,rcx                             | rcx:"th"
0000000141636FC3 | 48:8B0D A62C3601         | mov rcx,qword ptr ds:[142999C70]        | rcx:"th"
0000000141636FCA | 48:85C9                  | test rcx,rcx                            | rcx:"th"
0000000141636FCD | 74 0B                    | je wowclassic.141636FDA                 |
0000000141636FCF | 41:B8 02000000           | mov r8d,2                               |
0000000141636FD5 | E9 96E63FFF              | jmp wowclassic.140A35670                |
0000000141636FDA | C3                       | ret                                     |

3.追出包地址和包长 及 加密过程

1
2
3
4
5
6
7
000000014160FF97    FF15 13228D00    call qword ptr ds:[141EE21B0]    发包CALL 0
000000014161038F    E8 8CFBFFFF        call wowclassic.14160FF20        发包CALL 00
0000000141627E5A    E8 61AFFEFF        call wowclassic.141612DC0        发包CALL 000
0000000141610756    FF50 08            call qword ptr ds:[rax+8]        发包CALL 0000
0000000140A35616    E8 C5B0BD00        call wowclassic.1416106E0        发包CALL 00000
0000000140A356DB    E8 20FDFFFF        call wowclassic.140A35400        发包CALL 000000
0000000140BF1E24    E8 9751A400        call wowclassic.141636FC0        发包CALL 0000000

我们从第一个开始看 知道 rdx是包地址 r8就是长度 我们都追下

1
2
3
000000014160FF8E | 45:33C9                  | xor r9d,r9d                          |
000000014160FF91 | 44:8BC5                  | mov r8d,ebp                          |
000000014160FF94 | 49:8BD6                  | mov rdx,r14                          | r14  包长   ebp  包长

继续追 r14 和 ebp

1
2
000000014160FF72 | 4C:8B32                  | mov r14,qword ptr ds:[rdx]           | [rdx]  包长   ebp  包长
000000014160FF2B | 8B6A 10                  | mov ebp,dword ptr ds:[rdx+10]        | [rdx]  包长   [rdx+10]  包长

image-20210506161211937

 

这里被混淆了 我们需要从他上个CALL 进来看下 那个是函数头

 

image-20210506161228023

 

我们继续去00那里追 rdx

1
2
3
4
0000000141610389 | 48:8BD7                  | mov rdx,rdi                          | [rdi]  包长   [rdi+10]  包长
0000000141610365 | 48:8BFA                  | mov rdi,rdx                          | [rdx]  包长   [rdx+10]  包长
0000000141627E54 | 49:8BD7                  | mov rdx,r15                          | [r15]  包长   [r15+10]  包长
0000000141627CD0 | 4C:8D7C24 20             | lea r15,qword ptr ss:[rsp+20]        | [rsp+20]  包长   [rsp+20+10]  包长  这里只给了地址 里面是空的

image-20210506161335576

 

这里我们下段发现rsp+20是空的 说明 这个只是给他一个地址 赋值 在下面 我们标注下

 

我们下段来看下 他是那里给他赋值的 我们方法是 这里下段 看下他的地址里面的值 单步往下走 看什么时候被改变

 

image-20210506161409274

 

我们单步走下看看 那里改变了 这里的值

 

image-20210506161430378

1
0000000141627D00 | 41:890408                | mov dword ptr ds:[r8+rcx],eax        | 这里给包长赋值

image-20210506161524482

1
0000000141627D33 | E8 B8A1FEFF              | call wowclassic.141611EF0            | 这里给包地址-10 包长+10  猜测是添加包头

我们这个时候可以进去看下 是不是

 

image-20210506161559110

 

看似是一个包 我们继续单步

 

image-20210506161631594

1
0000000141627D3B | 8918                     | mov dword ptr ds:[rax],ebx           | 这里把我们原来的包长给前四个字节

那这里看似就是我们的明文完整包了 下面就是加密了 这里如果我们看不出来 我们可以去通过条件断点 来下一个喊话的发包看看是否我们猜想的这样

 

image-20210506161705073

 

这里可以看到是我们的明文包

 

image-20210506161722799

 

经过这里之后给我们加了0x10长度的数据 不知道是什么 后面我们在去看是什么 我们先继续单步

 

image-20210506161741666

 

这里把原来的包长给了我们的包头的前4个字节 我们继续往下跟

 

image-20210506161802011

 

经过这里的时候我们发现他的包体被加密了

1
0000000141627DA1 | E8 BA754100              | call wowclassic.141A3F360            | 加密包体

image-20210506161844526

 

发现红色包里面被改变了 正好是1B长度 我们可以得到那个1B是要加密的包长

 

image-20210506161859968

1
0000000141627DF4 | F241:0F114424 04         | movsd qword ptr ds:[r12+4],xmm0      | 改变包头+4 +B位置的这8个字节

继续往下看

 

image-20210506161950637

1
0000000141627E4F | 41:894424 0C             | mov dword ptr ds:[r12+C],eax         | 这里改变了 包头+C 到 +F位置的字节

然后就是我们本来的r15 最后send 就OK了 这样我们去找下 +4 到 +F分别是来源于什么吧 这C个字节

 

image-20210506162014582

 

这里我们可以看到 是来源于rbp+10 我们往上看看 那里又可以能是rbp+10

 

image-20210506162028213

 

他上面有个CALL 是取了 rbp+10的地址 一般取地址 都是要往里面写数据 我们这里下段看看是不是这里往下写的内容

 

image-20210506162041959

 

目前rbp+10是空 我们过去这个CALL

 

image-20210506162059641

 

然后给了这些 我们走到发包CALL 看看是否是这个值

 

image-20210506162115642

 

果然 我们包头的4到F 这C个字节 被这个CALL 过后的rbp+10里面的前C个字节给赋值了 这样我们就得到

1
0000000141627DE3 | E8 A8824100              | call wowclassic.141A40090            | 生成包头4-F 这13个字节需要的值 存放于rbp+10的前C个字节
  • 首先我们获取到一个明文包内容但是里面不全部是我们的内容 长度也是加密长度 经过一个CALL 后 我们包长+10 这时候 这+10字节是我们的包头
  • 然后给我们的包头 前4个字节 我们的加密包长 经过这个加密包长给我们原来的包进行一个CALL里面加密(俗称包体加密CALL)
  • 然后继续 给包头+4到+F位置 进行赋值 这个值是来自己上面这个给CALL的 rbp+10里面 因为这个CALL的参数里面有一个是rbp+10的地址
  • 经过这个CALL之后这里面的值改变了

4.最内层明文封包CALL 分析

我们去到最内层明文发包CALL 看下

 

首先我们要确定参数 我们进去这个CALL 看下

 

image-20210506162340642

 

rcx 的值 给了别的寄存器 说明 rcx用到了

 

image-20210506162356000

 

rdx也用到了

 

image-20210506162410999

 

r8 好像只用到了低32位

 

r9 是别人赋值过来的 看似没有用到 我们 先分析rcx rdx r8d 这三个吧

 

image-20210506162424241

 

首先看到 rdx 是包地址 rdx+0x10 存放的是包长

1
2
3
000000000014D9C0 00000000233A7F80 ..:#....
000000000014D9C8 0000000000000000 ........
000000000014D9D0 0000001000000012 ........

然后我们看包地址中的包内容

1
2
3
4
5
00000000233A7F80 00050000000737E7 ç7......
00000000233A7F88 3837363534333231 12345678
00000000233A7F90 0000000000003039 90......
 
可以看到 长度 12 就是我们发送的数据结尾 到30我们发的数据就是1234567890 就说明 这个12是总包长 然后我们现在不知道就是 00050000000737E7 这写是什么 我们在发个包看看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
000000000014D9C0 0000000021D58320  .Õ!....
000000000014D9C8 0000000000000000 ........
000000000014D9D0 0000001000000018 ........
 
0000000021D58320 00080000000737E7 ç7......
0000000021D58328 3131313131313131 11111111
0000000021D58330 3131313131313131 11111111
可以看到 变成了 00080000000737E7  我们基本可以判断 0000000737E7 是相等的 那么为什么是后2字节是00080005呢 我们看下
第一次 我们发送1234567890  10长度 是5
第二次 我们发送1111111111111111  16长度 是8
看似是我们长度的一半  我们去构建一个 试试
 
00060000000737E7
3131313131313131
        31313131
发送121 看看我们的看看我们的额包内容是不是这个

image-20210506162551874

 

和我们想象的是一样的 那么 我们如果发送的长度是13 会是怎样的呢

1
2
3
4
5
6
000000001FEB1C40 80060000000737E7 ç7......
000000001FEB1C48 3131313131313131 11111111
000000001FEB1C50 0000003131313131 11111...
 
发现 其他没什么变换  就是最后一个字节 从 00 变成了80
经过我们多次的设计和测试 发现 /2 整除是00 有余是80  也就是我们发送的包长奇数是80  偶数是00

r8d 经过分析发现是恒不变的1 rcx后面再去分析 是一个表达式 从下网上推就OK了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
000000014166C7EC | 48:8B8B E0000000         | mov rcx,qword ptr ds:[rbx+E0]        | 参数1  [rbx+E0]
 
000000014166C7AC | 48:8BD9                  | mov rbx,rcx                          | 参数1  [rcx+E0]
 
0000000140A69000 | 48:8B8CFB 90010000       | mov rcx,qword ptr ds:[rbx+rdi*8+190] | 参数1  [[rbx+rdi*8+0x190]+E0]
测试了rdi == 0
 
0000000140A68E28 | 48:8BD9                  | mov rbx,rcx                          | 参数1  [[rcx+rdi*8+0x190]+E0]
 
0000000140A690E8 | 48:8BCE                  | mov rcx,rsi                          | 参数1  [[rsi+rdi*8+0x190]+E0]
 
0000000140A690A8 | 48:8BF1                  | mov rsi,rcx                          | 参数1  [[rcx+rdi*8+0x190]+E0]
 
0000000141693073 | 48:8B0D F63B3601         | mov rcx,qword ptr ds:[1429F6C70]     | 参数1  [[[0x00000001429F6C70]+rdi*8+0x190]+E0]
0000000141693073 | 48:8B0D F63B3601         | mov rcx,qword ptr ds:[1429F6C70]     | 参数1  [[[wowclassic.exe + 0x29F6C70]+rdi*8+0x190]+E0]

通过简单的推算就推出了检测封包 下面我们去VS里面调用一下他

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
void CDLG_MAIN::OnBnClickedButton2()
{
    // TODO: 在此添加控件通知处理程序代码
 
    BYTE b_packet[18] = {0xE7, 0X37, 0X07, 0X00, 0X00, 0X00, 0X05, 0x00, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 };
    DWORD dw_temp_array[6] = { 0, 0, 0, 0, 0x12, 0x10 };
    *(QWORD*)dw_temp_array = (QWORD)b_packet;
    QWORD qw_rdx = (QWORD)dw_temp_array;
    fun_send_call(base_send, qw_rdx, 1);
}
 
__declspec(naked) void fun_send_call(QWORD qw_rcx,QWORD qw_rdx,DWORD dw_r8d)
{
    __asm
    {
        push rax
        sub rsp, 0x100
        add rcx, base_module_base
        mov rcx, [rcx]
        add rcx, offset_send_one
        mov rcx, [rcx]
        add rcx, offset_send_two
        mov rcx, [rcx]
        mov rax, [rcx]
        add rax, 0x8
        mov rax, [rax]
        call rax
        add rsp, 0x100
        pop rax
        retn
    }
}

5.Hook send函数

因为找个游戏 有些保护 如果直接修改他的代码 是不行的 所以 我们只能从send下手 从堆栈找出需要的数据

 

Hook 就不多说了 直接贴代码把

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
33
34
35
36
37
38
39
40
41
42
43
44
void CDLG_MAIN::OnBnClickedButton3()
{
    // TODO: 在此添加控件通知处理程序代码
    fun_hook_send();
}
 
 
void CDLG_MAIN::OnBnClickedButton4()
{
    // TODO: 在此添加控件通知处理程序代码
    fun_reduction_send();
}
 
void fun_hook_send()
{
    g_hook_send = new CInlineHook((__int64)send, (__int64)fun_send_proc,false,15);
    g_hook_send->MotifyAddress();
}
 
void fun_reduction_send()
{
    g_hook_send->RestoreAddress();
    delete g_hook_send;
    g_hook_send = nullptr;
}
 
 
//    __int64 fun_send_proc_jmp = ((__int64)send + 15);
void fun_send_proc()
{
    /*
        00007FFDDDC21210 | 48:895C24 08             | mov qword ptr ss:[rsp+8],rbx         | [rsp+8]:&"P#F凖\x7F"
        00007FFDDDC21215 | 48:896C24 10             | mov qword ptr ss:[rsp+10],rbp        |
        00007FFDDDC2121A | 48:897424 18             | mov qword ptr ss:[rsp+18],rsi        |
    */
    //    这里如果是CALL进来的 rsp要+8 所以后面每个都要+8
    __asm
    {
        mov qword ptr ss : [rsp + 0x10], rbx
        mov qword ptr ss : [rsp + 0x18], rbp
        mov qword ptr ss : [rsp + 0x20], rsi
        retn
    }
}
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
HOOK类
CInlineHook.h
 
#pragma once
#include <windows.h>
#include <stdio.h>
 
 
class CInlineHook
{
private:
#ifndef _WIN64
    using uchar = unsigned char;
    uchar* m_cOriginalByte;                        //原始OPCODE
    uchar* m_cMyByte;                            //自己的OPCODE
 
    int m_nOriginalAddress;                        //原始地址
    int m_nMyAddress;                            //自己的函数地址
    int m_nHookLen;
 
    DWORD MotifyMemProtect(int nAddress,DWORD dwProtect = PAGE_EXECUTE_READWRITE);
#else
    using uchar = unsigned char;
    uchar* m_cOriginalByte;                            //原始OPCODE
    uchar* m_cMyByte;                                //自己的OPCODE
 
    __int64 m_nOriginalAddress;                        //原始地址
    __int64 m_nMyAddress;                            //自己的函数地址
    int m_nHookLen;
    DWORD MotifyMemProtect(__int64 nAddress, DWORD dwProtect = PAGE_EXECUTE_READWRITE);
#endif
 
public:
#ifndef _WIN64
    //    bPattern  true 为jmp   false 为call
    CInlineHook(int nOriginalAddress, int nMyAddress, bool bPattern = true, int nHookLen = 5);
#else
    //    bPattern  true 为jmp   false 为call
    CInlineHook(__int64 nOriginalAddress, __int64 nMyAddress, bool bPattern = true, int nHookLen = 12);
#endif
 
    void MotifyAddress();
 
    void RestoreAddress();
 
    ~CInlineHook();
};
 
 
CInlineHook.cpp
 
#include "pch.h"
#include "CInlineHook.h"
 
CInlineHook::~CInlineHook()
{
    delete[] m_cMyByte;
    m_cMyByte = nullptr;
    delete[] m_cOriginalByte;
    m_cOriginalByte = nullptr;
}
 
void CInlineHook::MotifyAddress()
{
    DWORD dwProtect = MotifyMemProtect(m_nOriginalAddress);
 
    memcpy(reinterpret_cast<void*>(m_nOriginalAddress), m_cMyByte, m_nHookLen);
 
    MotifyMemProtect(m_nOriginalAddress, dwProtect);
}
 
void CInlineHook::RestoreAddress()
{
    DWORD dwProtect = MotifyMemProtect(m_nOriginalAddress);
 
    memcpy(reinterpret_cast<void*>(m_nOriginalAddress), m_cOriginalByte, m_nHookLen);
 
    MotifyMemProtect(m_nOriginalAddress, dwProtect);
}
 
#ifndef _WIN64
 
DWORD CInlineHook::MotifyMemProtect(int nAddress, DWORD dwProtect)
{
    DWORD dwOldProtect;
    VirtualProtect(reinterpret_cast<void*>(nAddress), m_nHookLen, dwProtect, &dwOldProtect);
    return dwOldProtect;
}
 
CInlineHook::CInlineHook(int nOriginalAddress, int nMyAddress, bool bPattern, int nHookLen)
    :m_nOriginalAddress(nOriginalAddress), m_nMyAddress(nMyAddress), m_nHookLen(nHookLen)
{
    m_cMyByte = new uchar[nHookLen];
    m_cOriginalByte = new uchar[nHookLen];
    if (bPattern)
    {
        m_cMyByte[0] = '\xE9';
    }
    else
    {
        m_cMyByte[0] = '\xE8';
    }
 
    int nOffset = nMyAddress - (nOriginalAddress + 5);
 
    memcpy(&m_cMyByte[1], &nOffset, 4);
 
    for (int i = 0; i < nHookLen - 5; i++) {
 
        m_cMyByte[i + 5] = '\x90';
    }
 
 
    DWORD dwProtect = MotifyMemProtect(nOriginalAddress);
 
    memcpy(m_cOriginalByte, reinterpret_cast<void*>(nOriginalAddress), m_nHookLen);
 
    MotifyMemProtect(nOriginalAddress, dwProtect);
}
 
#else
 
DWORD CInlineHook::MotifyMemProtect(__int64 nAddress, DWORD dwProtect /*= PAGE_EXECUTE_READWRITE*/)
{
    DWORD dwOldProtect;
    VirtualProtect(reinterpret_cast<void*>(nAddress), m_nHookLen, dwProtect, &dwOldProtect);
    return dwOldProtect;
}
 
CInlineHook::CInlineHook(__int64 nOriginalAddress, __int64 nMyAddress, bool bPattern /*= true*/, int nHookLen /*= 12*/)
    :m_nOriginalAddress(nOriginalAddress), m_nMyAddress(nMyAddress), m_nHookLen(nHookLen)
{
    m_cMyByte = new uchar[nHookLen];
    m_cOriginalByte = new uchar[nHookLen];
    m_cMyByte[0] = '\x48';
    m_cMyByte[1] = '\xB8';
    memcpy(&m_cMyByte[2], &nMyAddress,8);
    m_cMyByte[10] = '\xFF';
    if (bPattern)
    {
        m_cMyByte[11] = '\xE0';
    }
    else
    {
        m_cMyByte[11] = '\xD0';
    }
    if (nHookLen > 12)
    {
        for (int i = 12; i < nHookLen; i++)
        {
            m_cMyByte[i] = '\x90';
        }
    }
 
    DWORD dwProtect = MotifyMemProtect(nOriginalAddress);
 
    memcpy(m_cOriginalByte, reinterpret_cast<void*>(nOriginalAddress), m_nHookLen);
 
    MotifyMemProtect(nOriginalAddress, dwProtect);
}
 
#endif

6. 堆栈数据找出类似明文封包

我们最内层明文包是send返回第3层 最外层明文包是send返回第6层 之前我们可以得到 所以我们要找他的数据 我们只要在3-6之前找就OK了 我们来看下

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
000000000014D958  000000014166C809  返回到 wowclassic.000000014166C809 自 ???
000000000014D960  00000000005688A0 
000000000014D968  0000000000000001 
000000000014D970  0000000000568AB0 
000000000014D978  0000000000000012 
000000000014D980  000000000056D680 
000000000014D988  0000000140A6902B  返回到 wowclassic.0000000140A6902B 自 wowclassic.000000014166C790
000000000014D990  0000000000000000 
000000000014D998  000000000056D610 
000000000014D9A0  0000000000000000 
000000000014D9A8  00000001404A31BD  返回到 wowclassic.00000001404A31BD 自 wowclassic.00000001401C9940
000000000014D9B0  000000000014DA00 
000000000014D9B8  000000000014DA54 
000000000014D9C0  000000002405CC60 
000000000014D9C8  0000000000000000 
000000000014D9D0  0000001000000012 
000000000014D9D8  0000000100000000 
000000000014D9E0  0000000000000000 
000000000014D9E8  0000000000000000 
000000000014D9F0  00000000335B08C0  &"@灚@\x01"
000000000014D9F8  0000000000000000 
000000000014DA00  0000000000000002 
000000000014DA08  000000000056D610 
000000000014DA10  0000000141F55DC0  wowclassic.0000000141F55DC0
000000000014DA18  0000000140A690F0  返回到 wowclassic.0000000140A690F0 自 wowclassic.0000000140A68E10

我们去看下这些地址

 

image-20210506163431555

 

可以看出 在rsp+0x320处可以看到类似明文的地方

 

又因为我们要过滤心跳包 所以 这里要看下 +0x310处的地址 是否为

 

image-20210506163454933

 

如果不是这个就是心跳包或者别的包 我们不需要 我们只要功能CALL

 

+0x310是不完整 或者 太完整的明文包 然后 r8是我们的长度 好的 我们知道了这些之后就可以了

 

image-20210506163512608

 

可以看出 心跳+0x310是个看不懂的东西了 不是返回到 说嘛心跳包 就没有走到这个CALL

 

image-20210506163559183

1
2
喊话断下 也是这里 我们给他记录下
0x140A690F0  == wowclassic.exe + 0xA690F0
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
void fun_send_proc()
{
    /*
        00007FFDDDC21210 | 48:895C24 08             | mov qword ptr ss:[rsp+8],rbx         | [rsp+8]:&"P#F凖\x7F"
        00007FFDDDC21215 | 48:896C24 10             | mov qword ptr ss:[rsp+10],rbp        |
        00007FFDDDC2121A | 48:897424 18             | mov qword ptr ss:[rsp+18],rsi        |
    */
    //    这里如果是CALL进来的 rsp要+8 所以后面每个都要+8
    __asm
    {
        push rax
        ; 这里因为push了 所以 + 0x310变成了 + 0x318
        mov rax, [rsp + 0x318]
        mov hook_send_rsp_cmp, rax
        ; +0x320里面存放的就是数据
        mov rax, [rsp + 0x328]
        mov get_hook_send_packet, rax
        mov get_hook_send_len, r8
        pop rax
    }
 
    //    这里如果相等就说明是功能明文包 不然就心跳包 直接过滤
    get_hook_send_rsp_0x310 = (__int64)base_module_base + base_hook_send_rsp_0x310;
    if (hook_send_rsp_cmp == get_hook_send_rsp_0x310)
    {
        __asm
        {
            push rax
            push rbx
            push rcx
            push rdx
            push rsi
            push rdi
            push r8
            push r9
            push r10
            push r11
            push r12
            push r13
            push r14
            push r15
            sub rsp,0x100
        }
        fun_out_packet_text();
        __asm
        {
            add rsp,0x100
            pop r15
            pop r14
            pop r13
            pop r12
            pop r11
            pop r10
            pop r9
            pop r8
            pop rdi
            pop rsi
            pop rdx
            pop rcx
            pop rbx
            pop rax
        }
 
    }
 
    __asm
    {
        mov qword ptr ss : [rsp + 0x8], rbx
        mov qword ptr ss : [rsp + 0x10], rbp
        mov qword ptr ss : [rsp + 0x18], rsi
        jmp fun_send_proc_jmp
    }
}
 
void fun_hook_send()
{
    g_hook_send = new CInlineHook((__int64)send, (__int64)fun_send_proc,true,15);
    g_hook_send->MotifyAddress();
}
 
void fun_reduction_send()
{
    g_hook_send->RestoreAddress();
    delete g_hook_send;
    g_hook_send = nullptr;
}
 
void fun_out_packet_text()
{
    printf("长度:%d", get_hook_send_len);
    byte *ptr = 0;
    char str_temp[0x2000];
    char str_out[0x2000] = "";
    for (__int64 i = 0; i < get_hook_send_len; i++)
    {
        sprintf_s(str_temp, "%02X", *(byte*)(get_hook_send_packet + i));
        strcat_s(str_out, str_temp);
    }
    printf("\t\t\t明文包内容:%s\r\n", str_out);
    delete ptr;
    if (ptr != nullptr)
    {
        ptr = nullptr;
    }
}
我们这里已经能正确输出所有的功能CALL的函数了

image-20210506163742129

 

可以发现 喊话内容只有一部分是对的 我们需要去修改 我们继续去看下 我们这个明文包 和 第外层明文包 和 最内层明文包的区别 转换成最内层明文包 因为我们需要自己去调用最内层明文包 然后 自己加密 和发包

7.分析堆栈包和最内层明文包和最外层明文包的关系

1
2
0000000140A690EB | E8 20FDFFFF              | call wowclassic.140A68E10            | 最外层明文包
000000014166C806 | FF50 08                  | call qword ptr ds:[rax+8]            | 最内层明文包

+0x320地址的明文包

1
2
3
4
5
6
000000000014DAE0 0000000142185CE8 è\.B.... "@刅@\x01"
000000000014DAE8 8000001200000000 ........
000000000014DAF0 0000000000000000 ........
000000000014DAF8 0000000000000000 ........
000000000014DB00 3131313100000007 ....1111
000000000014DB08 0000313131313131 111111..

最外层明文包 rdx+8是包地址 rdx+0x18是包长度

1
2
3
4
5
6
包地址里面是这样的
00000000310D4390 00000000310D3E90 .>.1.... &"怑\r1"
00000000310D4398 FFFF000142591BE0 à.YB..ÿÿ
00000000310D43A0 00050000000737E7 ç7......
00000000310D43A8 3131313131313131 11111111
00000000310D43B0 0000000000003131 11......

最内层明文包 rdx 包地址 rdx+0x10是包长度

1
2
3
0000000021FB6710 00050000000737E7 ç7......
0000000021FB6718 3131313131313131 11111111
0000000021FB6720 0000000000003131 11......

我们可以看出 最外层明文包 和 最内层明文包 多了 16个字节 我们可以砍掉 就OK了 那么我们怎么才能通过+0x320的封包 得到最外层的封包呢

 

image-20210506163858731

 

我们可以看到 这里 也就是 最外层明文包的这里+8的位置就是我们+0x320的包 因为 rsp是不会变的

 

image-20210506164000215

 

我们看下 这个rsp+0x28这里 到底是哪里给他改了

 

image-20210506164012932

 

那我们来分析下这个CALL就好了呢

1
2
3
4
5
6
0000000140A690CA | 48:8B03                  | mov rax,qword ptr ds:[rbx]           |
0000000140A690CD | 48:8D5424 20             | lea rdx,qword ptr ss:[rsp+20]        |
0000000140A690D2 | 48:8BCB                  | mov rcx,rbx                          |
0000000140A690D5 | FF50 10                  | call qword ptr ds:[rax+10]           | 这个CALL 讲内容转换成了 最内层的明文包
 
可以看出 这个CALL就是只有 两个参数 rcx和rdx  还有一个CALL rax  rax来自 rbx  rcx来自rbx  也就是 我们只要找处 rbx和rdx即可

image-20210506164045980

 

这里我们可以看出 rbx和我们+0x320获取的值是一样的 这样我们要看下 rsp+0x20哪里是什么

1
2
3
4
5
6
7
8
9
10
11
000000000014DA40 0000000141F55DC0 À]õA.... wowclassic.0000000141F55DC0
000000000014DA48 0000000022218F10 ..!"....
000000000014DA50 0000010000000000 ........
000000000014DA58 FFFFFFFF00000010 ....ÿÿÿÿ
000000000014DA60 0000000000000001 ........
 
可以看到      +0 就是个 基址 wowclassic.exe + 0x1F55DC0
            +8  看似是个申请出来的地址 每次都会变 存放的就是 下面第一张图
            +10 是个固定的值0000010000000000
            +18 运行CALL 之后被填入长度
            +20 就是一个固定的1

image-20210506164134802

 

我们获取+0x320处的代码 转换之后就可以获取到最外层的明文CALL 然后经过 减去前0x10个字节 就是完整的明文包了 可以去写下代码

8.完成转换 输出封包内容

image-20210506164209279

 

用代码修改获取下 发现就是正确的明文封包了

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//    明文解析  解析0x320处的明文封包解析成最外层明文封包
__declspec(naked) void fun_plaintext_parsing(QWORD qw_rcx, QWORD qw_rdx)
{
    /*
        0000000140A690CA | 48:8B03                  | mov rax,qword ptr ds:[rbx]           |
        0000000140A690CD | 48:8D5424 20             | lea rdx,qword ptr ss:[rsp+20]        |
        0000000140A690D2 | 48:8BCB                  | mov rcx,rbx                          |
        0000000140A690D5 | FF50 10                  | call qword ptr ds:[rax+10]           | 这个CALL 讲内容转换成了 最内层的明文包
    */
    __asm
    {
            push rax
            sub rsp,0x100
 
            mov rax, get_hook_send_packet
            mov rax, [rax]
            add rax, 0x10
            call[rax]
 
            add rsp, 0x100
            pop rax
            retn
 
    }
}
 
void fun_out_packet_text()
{
    QWORD qw_rdx;
    QWORD qw_rcx = get_hook_send_packet;
    QWORD qw_one = (__int64)base_module_base + base_packet_to_call_stc_address;
    BYTE* ptr_packet = new BYTE[100];
    QWORD qw_stc[5] = { qw_one,(QWORD)ptr_packet,0x0000010000000000,0xFFFFFFFF00000010,1 };
    qw_rdx = (QWORD)&qw_stc;
    //printf("rcx   ==  %I64d", &qw_rcx);
    //printf("rdx   ==  %I64d", &qw_rdx);
 
    fun_plaintext_parsing(qw_rcx, qw_rdx);
    byte *ptr = 0;
    char str_temp[0x2000] = "";
    char str_out[0x2000] = "";
    DWORD dw_len = (DWORD)qw_stc[3];
    printf("长度:%d", dw_len - 0x10);
    QWORD qw_address = qw_stc[1] + 0x10;                                        //    获取存取明文包地址   
    for (__int64 i = 0; i < dw_len - 0x10; i++)
    {
        //printf("地址 == %I64d", qw_address + i);
        sprintf_s(str_temp, "%02X", *(byte*)(qw_address + i));
        strcat_s(str_out, str_temp);
    }
    printf("\t\t\t明文包内容:%s\r\n", str_out);
    delete ptr;
    delete ptr_packet;
    if (ptr != nullptr)
    {
        ptr = nullptr;
    }
    if (ptr_packet != nullptr)
    {
        ptr_packet = nullptr;
    }
}

第五届安全开发者峰会(SDC 2021)议题征集正式开启!

收藏
点赞4
打赏
分享
最新回复 (20)
雪    币: 206
活跃值: 活跃值 (825)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yy虫子yy 活跃值 2021-5-6 22:06
2
0
魔兽怀旧检测越来越严了
雪    币: 479
活跃值: 活跃值 (782)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Kaining 活跃值 2021-5-6 23:27
3
0
yy虫子yy 魔兽怀旧检测越来越严了
是的 越来越严了 动不动就掉
雪    币: 15574
活跃值: 活跃值 (18181)
能力值: (RANK:75 )
在线值:
发帖
回帖
粉丝
Editor 活跃值 2021-5-7 11:24
4
0
感谢分享
雪    币: 319
活跃值: 活跃值 (178)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
挥一挥衣袖 活跃值 2021-5-7 12:44
5
0
mark,学习经验,感谢分享
雪    币: 207
活跃值: 活跃值 (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
鱿鱼哥 活跃值 2021-5-12 18:30
6
0
请问您用的什么哪个调试器,是x64dbg吗?求教怎么过的反调试
雪    币: 479
活跃值: 活跃值 (782)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Kaining 活跃值 2021-5-12 23:44
7
0
鱿鱼哥 请问您用的什么哪个调试器,是x64dbg吗?求教怎么过的反调试[em_51]
x
64dbg
雪    币: 207
活跃值: 活跃值 (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
鱿鱼哥 活跃值 2021-5-13 14:31
8
0
轩词 x 64dbg
有偿求教过反调试,能否给个联系方式?
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_hemqlhwj 活跃值 2021-5-19 15:57
9
0
你好,请问第一步“找出什么函数发包”这是用什么软件来判断的?
雪    币: 479
活跃值: 活跃值 (782)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Kaining 活跃值 2021-5-19 16:11
10
0
mb_hemqlhwj 你好,请问第一步“找出什么函数发包”这是用什么软件来判断的?
一般来讲 就三个 测试就好了  send  sendto WSASend 如果都不断 基本可以确定是重写了 可以到更里面WSPSend去看看
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_hemqlhwj 活跃值 2021-5-20 11:23
11
0
Kaining 一般来讲 就三个 测试就好了 send sendto WSASend 如果都不断 基本可以确定是重写了 可以到更里面WSPSend去看看
感谢师傅
雪    币: 20
活跃值: 活跃值 (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gthabckx 活跃值 2021-6-17 10:41
12
0
这个游戏不是有写保护吗,怎么HOOK的,我目前是HOOK user32.dll里面的某处来实现的,试过WOW64EXT方法 ntprotectvirtualmemory改写保护失败
雪    币: 20
活跃值: 活跃值 (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gthabckx 活跃值 2021-6-17 10:56
13
0
 我搞怀旧服快2年了,有成品,加个好友,一起学习下吧,Q 360758700
雪    币: 20
活跃值: 活跃值 (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gthabckx 活跃值 2021-6-17 10:58
14
0
我也是找到的这个发包函数,我是直接构造封包,然后CALL这个函数实现的
雪    币: 4
活跃值: 活跃值 (470)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yaoguen 活跃值 2021-6-17 20:15
15
0
这个代码x64用了汇编,怎么编译
雪    币: 2437
活跃值: 活跃值 (2453)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
baikaishiu 活跃值 2 2021-6-18 06:20
16
0

其实我不是特别理解为什么做外挂,需要分析封包?以前和另外一个朋友写外挂的时候,感觉封包有几个问题

1. 上下文复杂,你很难搞清除在发送 封包 A之前是否需要发送B, 或者C,而这个上下文甚至会依赖于具体的时间发生变化
2. 对理解系统没有帮助,你分析出了哪个函数是哪个功能,对理解另外一个功能帮助不大,你应该直接分析它的资源文件,以及它的脚本,现在的游戏引擎可以认为是一个简单的 MVC架构,资源文件算是 Model,材质图等算是View, 脚本是Control,把这部分解析出来,直接可以解开全部文件,看它的内部资源文件如何定义,然后它的脚本如何操作。这个方法前期慢,后期越来越快。

3. 分析引擎的资源加载和调度部分,对理解同公司的所有游戏,以及同引擎的同类游戏都有帮助
4. 用封包很容易触发风控,原因还是1的问题,你用封包可能站在离人物30 yard的位置对话,不用封包,用脚本模拟,只能走到15yard的位置,它也不报错,就后台慢慢记录,你怎么处理呢?

5. 用封包,无法规范合作人的用法,会导致很多人往变态挂上去靠,进一步惹怒玩家导致举报,各种穿墙,秒杀,都来自于这些不严格的用法,短期内获利,长期很容易做死。

最后于 2021-6-18 06:26 被baikaishiu编辑 ,原因:
雪    币: 479
活跃值: 活跃值 (782)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Kaining 活跃值 2021-6-18 09:38
17
0
baikaishiu 其实我不是特别理解为什么做外挂,需要分析封包?以前和另外一个朋友写外挂的时候,感觉封包有几个问题1.&nbsp;上下文复杂,你很难搞清除在发送&nbsp;封包&nbsp;A之前 ...
封包一般不就是测试用的吗 为啥让你说的这么神奇....
雪    币: 2437
活跃值: 活跃值 (2453)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
baikaishiu 活跃值 2 2021-6-18 09:45
18
0
Kaining 封包一般不就是测试用的吗 为啥让你说的这么神奇....
你说的对
雪    币: 571
活跃值: 活跃值 (129)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lylxd 活跃值 2021-6-18 12:38
19
0
想知道是怎么调试的,目前卡在我发call lua的情况。准备放弃了。
雪    币: 4
活跃值: 活跃值 (470)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yaoguen 活跃值 2021-6-21 18:45
20
0
Kaining 封包一般不就是测试用的吗 为啥让你说的这么神奇....
这个代码x64用了汇编,怎么编译
雪    币: 438
活跃值: 活跃值 (311)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小kcode 活跃值 5天前
21
0
楼主老板,留个QQ
游客
登录 | 注册 方可回帖
返回