[!Error]
本贴仅研究壳子本身,不涉及游戏内容,请勿在游戏内进行作弊行为!
0x0
《内核级反作弊》

《请输入文本》
0x1 日志
参考了别的佬的文档
gist.github.com https://gist.github.com/WitherOrNot/0c2974be82393265aa5fb8f82be1f0a1 htpec.md# Notes
These are very disorganized because I wrote these as I reversed various bits and pieces. If I'm wrong about something, please let me know so I can forget to update this.
## Logging
For me this was the Achilles' heel, Crackproof creates a debug log if a certain folder in `%temp%` is present. The folder name is 12 hex characters long, and different between executables. The easiest way to find it is to break on/hook `CreateFileW`.
Once you create it, any Crackproofed modules will spit out logs as they unpack. Lines contain status codes, indicating roughly what the unpacker is doing at a given time (see below). Lines with additional debug information are also included, sometimes they can be very handy.
此文件已被截断。 显示原始文件
对kernelbase.CreateFileW下断不难发现壳子在检查存放日志的文件夹是否存在,并且还会检查文件夹创建时间是否超过2天,否则不保存日志
创建文件夹以后正常启动一次游戏可以抓出以下的日志:
C:\priconner\sample\PrincessConnectReDive.exe
-CF -C2 -E2 -CC -T12 -RC3 -GWH -DA -DD -PP2 -EDD -I -EL5 -CK2 -CD1 -CD2 -CD3 -CD4 -CD5 -EVS -DE -DEP1 -DC -PD -NCP -NCP2 -NC -NE -NCC2 -NRC -NDA3 -NDDE -NEL -NEL2 -NEL3 -NEL4 -NELA -NERR -NWEB -NGMD
2026/04/18 23:56:10.197
00000001`40000000
200
000 00001000 00000000 ._
410
510
520
540
560
2026/04/18 23:56:12.083
561
C00
001 01A06658 01A037AB
C01
001 0003 0003 0000 0000
C02
001 Htsysm1B4001
002 1 2 PrincessConnectRedive64_.sys
C03
002 BCAB405E 36950000 03E8
003 PrincessConnectRedive64_.sys
004 0F000
C04
005 000005A0 000005E8 000005E0
003 03 00007FFC`21A9F7D0 ntdll.dll!LdrLoadDll
A09
A0F
A08
009 1
A07
002 01 00
5D0
552
570
00C 005F
00D 0000 0004 0000 0002 0002 0000 0000
010 00000001`400AB760
590
5B0
5B1
598
5A0
A06
5C0
5E1
5E2
610
640
655
6E1
800
001 00000001`400BB000
810
820
840
002 00000001`40052010 00000001`400B8D50 00000001`400B8C20
001 04F0
6E2
E20
014 003D20 1000 00000000`00000000
E40
00A 00000001`400C6800 000001A0
00B 0004 0002 0002 0001 0001 0000 0000
E52
E53
E54
E55
E59
660
280
2026/04/18 23:56:13.295
000-000-000
日志
解释
00000001`40000000
主exe的imagebase
200
壳子流程开始
000 00001000 00000000 ._
映射外置的_RDATA段
410
开始反调试
510
检查某块内存的CRC32
520
检查NtQueryInformationProcess
540
检查是否存在VMWare后面
560
代码段解密初始化
561
选择加载子模块(新版本似乎已弃用
C00
检查Windows版本
001 01A06658 01A037AB
0x01A0+26200 = 01A06658,代表 Windows 11 25H2;0x01A0+14251 = 01A037AB,代表 Windows 10 Insider Preview Build 14251;也就是至少Windows 10才能运行
C01
检查 BCD 启动参数
001 0003 0003 0000 0000
意义不明
日志
解释
C02
安装驱动服务
001 Htsysm1B4001
驱动设备名称
002 1 2 PrincessConnectRedive64_.sys
1代表SERVICE_KERNEL_DRIVER,2代表SERVICE_AUTO_START,最后是驱动名称,在C:\Windows\System32文件夹下面
日志
解释
C03
NtLoadDriver
002 BCAB405E 36950000 03E8
意义不明 意义不明 驱动IOCTL返回值
003 PrincessConnectRedive64_.sys
驱动文件名
004 0F000
SizeOfImage
日志
解释
C04
安装hook(?
005 000005A0 000005E8 000005E0
意义不明 意义不明 意义不明
003 PrincessConnectRedive64_.sys
驱动文件名
03 03 00007FFC`21A9F7D0 ntdll.dll!LdrLoadDll
LdrLoadDll所在地址
日志
解释
A09
反虚拟机,检测注册表路径里面是否以下面的字符串开头:Virtual,VMware,Bochs,VBOX,VRTUAL,Microsoft Hyper-V,Parallels(PD都检测是何意味)
A0F
检查dll注入:AppInit_DLLs,User32.dll,apphelp.dll,ShimEng.dll(不检查dxgi,winhttp,version?????)
A08
从磁盘拷贝干净的 ntdll/kernel32 代码到内存(hyperdbg:人尔女子)
A07
杀注入线程
注册表
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SystemInformation\SystemProductName
HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\BIOS\SystemProductName
HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\SystemBiosVersion
日志
解释
5D0
解密前置流程,handler为0x14005B694
552
解密前置流程,handler为0x140059AB5
570
解密前置流程,handler为0x14005A122
590
解密前置流程,handler为0x14005A5DC
5B0
解密前置流程,handler为0x14005A3E4
5B1
解密前置流程,handler为0x14005A728
598
解密前置流程,handler为0x14005AA0E
5A0
解密前置流程,handler为0x14005AAB3
A06
意义不明
5C0
运行时恢复模块的入口点(?
5E1
解密前置流程,handler为0x14005B483
5E2
解密前置流程,handler为0x14005B523
610
解密PE头
640
解密各个段
655
PE重定位
6E1
疑似收尾工作,似乎在重新加密部分text段
E55
检测openark驱动的设备名,检测到就自杀
E91
检测CE驱动的设备名,检测到就自杀
日志
解释
046-019-01F
内核驱动回调被禁用
048-012-002
检测到hyper-v虚拟机
601-000-008
检测到CE
0x2 动态解密
这部分仅针对公主连结Re:Dive DMM,Cygames就喜欢搞这种看似有用实际上完全没用的东西(笑
别的exe上面的crackproof没有这个功能,例如学园偶像大师DMM的内存就是正常的
以00007FFA5E889000为例,CE可以看到这里的内存属性为PAGE_NOACCESS

当CPU试图执行里面的指令就会触发异常
EXCEPTION_DEBUG_INFO:
dwFirstChance: 1
ExceptionCode: C0000005 (EXCEPTION_ACCESS_VIOLATION)
ExceptionFlags: 00000000
ExceptionAddress: gameassembly.00007FFA5E889000
NumberParameters: 2
ExceptionInformation[00]: 0000000000000008 DEP Violation
ExceptionInformation[01]: gameassembly.00007FFA5E889000 Inaccessible Address
这里会调用ntdll.KiUserExceptionDispatcher处理异常
→ ntdll.KiUserExceptionDispatcher 被壳 inline hook
00007FFB685E5AE0 E9 2B051000 jmp 00007FFB686E6010
跳到 ntdll .reloc 里面:
00007FFB686E6010 FF25 F2FFFFFF jmp qword ptr [00007FFB686E6008]
[7FFB686E6008] 再跳到壳里面
→ 7FF6AD977C00:ntdll.KiUserExceptionDispatcher hook dispatcher
7FF6AD977C00 8B0D 72210000 mov ecx, dword ptr [7FF6AD979D78] // 栈偏移
7FF6AD977C06 48 03 CC add rcx, rsp // rcx = rsp + offset 得到一个与当前异常恢复相关的结构指针,后续按 EXCEPTION_RECORD 布局读取。
7FF6AD977C09 48 83 EC 20 sub rsp, 20h
7FF6AD977C0D E8 AEDEFFFF call 7FF6AD975AC0 // 从异常记录里取 fault address
7FF6AD977C12 85 C0 test eax, eax
7FF6AD977C14 74 15 jz 7FF6AD977C2B
7FF6AD977C16 E8 F5DFFFFF call 7FF6AD975C10 // 处理异常
7FF6AD977C1B 85 C0 test eax, eax
7FF6AD977C1D 74 0B jz 7FF6AD977C2A
7FF6AD977C1F 48 83 C4 20 add rsp, 20h
7FF6AD977C23 48 8B CC mov rcx, rsp
7FF6AD977C26 33 D2 xor edx, edx
7FF6AD977C28 FF D0 call rax // 返回KiUserExceptionDispatcher
7FF6AD977C2A CC int3
7FF6AD977C2B E8 B0DFFFFF call 7FF6AD975BE0
7FF6AD977C30 48 83 C4 20 add rsp, 20h
7FF6AD977C34 FF E0 jmp rax // 返回KiUserExceptionDispatcher
→ 7FF6AD975AC0:从异常记录取 ExceptionAddress / ExceptionInformation[1]
7FF6AD975B0C 48 8B 77 28 mov rsi, qword ptr [rdi+28h]
7FF6AD975B10 48 8B 7F 10 mov rdi, qword ptr [rdi+10h]
...
7FF6AD975B41 8B CE mov ecx, esi
7FF6AD975B43 E8 98FDFFFF call 7FF6AD9758E0
...
7FF6AD975BA4 48 8B D7 mov rdx, rdi
7FF6AD975BA7 48 8B CE mov rcx, rsi
7FF6AD975BAA E8 D1FEFFFF call 7FF6AD975A80
对应 EXCEPTION_RECORD 布局
ExceptionRecord + 0x10 = ExceptionAddress
ExceptionRecord + 0x28 = ExceptionInformation[1]
→ 7FF6AD975A80:7FF6AD975910的wapper
→ 7FF6AD975910:定位 fault address 所属保护区域和页
7FF6AD975942 48 8D 44 24 30 lea rax, [rsp+30h]
7FF6AD975947 4C 8D 4C 24 68 lea r9, [rsp+68h]
7FF6AD97594C 4C 8D 44 24 60 lea r8, [rsp+60h]
7FF6AD975951 49 8B D4 mov rdx, r12
7FF6AD975954 48 8B CF mov rcx, rdi
7FF6AD975957 48 89 44 24 20 mov [rsp+20h], rax
7FF6AD97595C C7 44 24 60 0... mov dword ptr [rsp+60h], 0
7FF6AD975964 C7 44 24 68 0... mov dword ptr [rsp+68h], 0
7FF6AD97596C C7 44 24 30 0... mov dword ptr [rsp+30h], 0
7FF6AD975974 E8 F7F6FFFF call 7FF6AD975070 // 查找 fault address 属于哪个受保护区域
7FF6AD975979 48 8B 0D ... mov rcx, qword ptr [7FF6AD979D60]
7FF6AD975980 0F BA 69 04 1B bt dword ptr [rcx+4], 1Bh // 打印日志的开关
7FF6AD975985 48 8B D8 mov rbx, rax
7FF6AD975988 73 4F jnb 7FF6AD9759D9
7FF6AD9759D9 48 85 DB test rbx, rbx // 匹配到的区域描述符
7FF6AD9759DC 74 4B jz 7FF6AD975A29
7FF6AD9759DE 83 7C 24 60 00 cmp dword ptr [rsp+60h], 0 // 是是否需要解密
7FF6AD9759E3 74 44 jz 7FF6AD975A29
7FF6AD9759E5 FF15 ... call qword ptr [<&GetTickCount>]
7FF6AD9759EB 8905 ... mov dword ptr [7FF6AD979D50], eax
...
7FF6AD975A19 2B 7B 08 sub edi, dword ptr [rbx+8]
7FF6AD975A1C 48 8B CB mov rcx, rbx
7FF6AD975A1F C1 EF 0C shr edi, 0Ch
7FF6AD975A22 8B D7 mov edx, edi // edi = (fault_address - region_base) >> 12 得到 page index
7FF6AD975A24 E8 67F1FFFF call 7FF6AD974B90 // page handler
→ 7FF6AD975070:查找区域和页描述符
7FF6AD9750AA 44 8B 1D ... mov r11d, dword ptr [7FF6AD979D6C] // region count
7FF6AD9750C6 48 8D 0D ... lea rcx, [7FF6AD978D50] // region table
loop:
7FF6AD9750D0 48 8B 11 mov rdx, qword ptr [rcx]
7FF6AD9750D3 4C 8B 42 08 mov r8, qword ptr [rdx+8] // region base
7FF6AD9750D7 49 3B D8 cmp rbx, r8 // fault < base?
7FF6AD9750DA 72 0C jb next
7FF6AD9750DC 48 63 42 10 movsxd rax, dword ptr [rdx+10h] // region size
7FF6AD9750E0 49 03 C0 add rax, r8
7FF6AD9750E3 48 3B D8 cmp rbx, rax // fault < base+size?
7FF6AD9750E6 72 39 jb found
找到所属区域后:
7FF6AD97514D 2B 5A 08 sub ebx, dword ptr [rdx+8]
7FF6AD975150 C1 EB 0C shr ebx, 0Ch // page index
7FF6AD975153 3B 5A 24 cmp ebx, dword ptr [rdx+24h] // page count
7FF6AD975158 48 63 42 20 movsxd rax, dword ptr [rdx+20h] // page table offset
7FF6AD97515C 8B CB mov ecx, ebx
7FF6AD97515E 48 C1 E1 04 shl rcx, 4 // page_desc size = 0x10
7FF6AD975162 48 03 C8 add rcx, rax
7FF6AD975165 48 03 4A 08 add rcx, qword ptr [rdx+8] // page_desc VA
7FF6AD975169 8B 01 mov eax, dword ptr [rcx]
7FF6AD97516B 0F BA E0 18 bt eax, 18h
7FF6AD975171 C1 E8 10 shr eax, 10h
7FF6AD975174 83 E0 01 and eax, 1
7FF6AD975177 89 45 00 mov dword ptr [rbp], eax
推断结构体:
struct region_desc {
uint32_t flags; // +0x04 也有全局/区域标志
uint64_t base; // +0x08
uint32_t size; // +0x10
...
uint32_t page_off; // +0x20
uint32_t page_count; // +0x24
HANDLE mapping; // +0x28
uint32_t decrypt_cnt; // +0x34
};
struct page_desc {
uint32_t flags; // +0x00
uint32_t key_part; // +0x04
uint32_t last_tick; // +0x08
uint16_t hit_count; // +0x0C
uint16_t checksum; // +0x0E
};
→ 7FF6AD974B90: 解密准备工作
7FF6AD974BC1 BF 00000100 mov edi, 10000h
...
7FF6AD974BEE 48 8B 4B 28 mov rcx, qword ptr [rbx+28h]
7FF6AD974BF2 41 8D 50 06 lea edx, [r8+6]
7FF6AD974BF6 FF15 ... call qword ptr [<&MapViewOfFile>]
7FF6AD974BFC 48 63 7B 20 movsxd rdi, dword ptr [rbx+20h]
...
7FF6AD974C08 49 8B E8 mov r12, rax // mapped view
通过 MapViewOfFile 映射待处理页的数据,保存在r12
7FF6AD974C0F 48 C1 E1 04 shl rcx, 4
7FF6AD974C13 48 03 F9 add rdi, rcx
7FF6AD974C16 48 03 7B 08 add rdi, qword ptr [rbx+8]
page_desc = region_base + page_table_offset + page_index * 0x10
7FF6AD974C22 8B05 ... mov eax, dword ptr [7FF6AD979D50]
7FF6AD974C28 81 27 FFFF FEFF and dword ptr [rdi], 0FFFEFFFFh
7FF6AD974C2E 66 83 47 0C 01 add word ptr [rdi+0Ch], 1
7FF6AD974C33 89 47 08 mov dword ptr [rdi+8], eax
7FF6AD974C36 83 43 34 01 add dword ptr [rbx+34h], 1
意义不明
7FF6AD974C3A 8B C5 mov eax, ebp
7FF6AD974C3C 41 2B C6 sub eax, r14d
7FF6AD974C3F BA 00100000 mov edx, 1000h
7FF6AD974C44 48 63 F0 movsxd rsi, eax
7FF6AD974C47 8B 43 08 mov eax, dword ptr [rbx+8]
7FF6AD974C4A 44 8D 44 05 00 lea r8d, [rbp+rax]
7FF6AD974C4F 49 03 F4 add rsi, r12
7FF6AD974C52 44 33 47 04 xor r8d, dword ptr [rdi+4]
7FF6AD974C56 48 8B CE mov rcx, rsi
7FF6AD974C59 E8 52FBFFFF call 7FF6AD9747B0
key = (page_va_related_value + region_base_low32) ^ page_desc->key_part
7FF6AD974C96 0F BA 27 14 bt dword ptr [rdi], 14h
7FF6AD974C9A 73 48 jnb 7FF6AD974CE4
7FF6AD974C9C 45 8B C5 mov r8d, r13d
7FF6AD974C9F BA 00100000 mov edx, 1000h
7FF6AD974CA4 48 8B CE mov rcx, rsi
7FF6AD974CA7 E8 84FBFFFF call 7FF6AD974830
二次解密(?
7FF6AD974CE4 48 63 CD movsxd rcx, ebp
7FF6AD974CE7 4C 8D 4C 24 68 lea r9, [rsp+68h]
7FF6AD974CEC BA 00100000 mov edx, 1000h
7FF6AD974CF1 48 03 4B 08 add rcx, qword ptr [rbx+8]
7FF6AD974CF5 41 B8 20000000 mov r8d, 20h
7FF6AD974CFB C7 44 24 68 0... mov dword ptr [rsp+68h], 0
7FF6AD974D03 FF15 ... call qword ptr [<&VirtualProtect>]
把page权限改成可执行,然后清理现场
VirtualProtect(region_base + page_index_or_offset, 0x1000, PAGE_EXECUTE_READ, &oldProtect)
→ 7FF6AD9747B0: 主解密函数
7FF6AD9747BF 44 8B D8 mov ebx, r8d
7FF6AD9747C2 8B F2 mov esi, edx
7FF6AD9747C4 48 8B F9 mov rdi, rcx
...
7FF6AD9747DC C1 EE 02 shr esi, 2
7FF6AD9747DF 41 C1 E0 10 shl r8d, 10h
7FF6AD9747E3 33 D2 xor edx, edx
7FF6AD9747E5 44 33 C3 xor r8d, ebx
7FF6AD9747EA 45 8B C8 mov r9d, r8d
loop:
7FF6AD9747F0 8B 0F mov ecx, dword ptr [rdi]
7FF6AD9747F2 44 03 C2 add r8d, edx
7FF6AD9747F5 83 C2 01 add edx, 1
7FF6AD9747F8 41 C1 C0 03 rol r8d, 3
7FF6AD9747FC 8B C1 mov eax, ecx
7FF6AD9747FE 48 83 C7 04 add rdi, 4
7FF6AD974802 41 33 C1 xor eax, r9d
7FF6AD974805 44 8B C9 mov r9d, ecx
7FF6AD974808 41 33 C0 xor eax, r8d
7FF6AD97480B 3B D6 cmp edx, esi
7FF6AD97480D 89 47 FC mov dword ptr [rdi-4], eax
7FF6AD974810 7C DE jl loop
void decrypt(uint32_t *buf, uint32_t size, uint32_t key)
{
uint32_t count = size >> 2;
uint32_t state = (key << 16) ^ key;
uint32_t prev = state;
for (uint32_t i = 0; i < count; i++) {
uint32_t enc = buf[i];
state = rol32(state + i, 3);
buf[i] = enc ^ prev ^ state;
prev = enc;
}
}
0x3 过保护
停用ProcessObCallback PRE和ProcessObCallback POST内核回调就能随意attach/inject/dump了,想干啥就干啥(笑
0x4
前置解密就不研究了,隔着在里面block套block,解密出来一个block跳进去跑,再解密一个block出来再跳进去跑,还会把上一个block加密回去,各种间接跳转用的飞起,trace日志随随便便就1GB了,给我逆红温了,压力codex这货也看不明白 ![]()
0xF 总结
非常垃圾的内核反作弊,完全过时的技术,只能看到吃老本的技术,看不到一点创新:
不检查PatchGuard,不检查Driver Signature Enforcement,不检查dll劫持,不检查堆栈回调,不过滤日志,混淆力度约等于0,隔壁ACE都在VT猛猛发力了,这玩意还在ring3吃老本
大名鼎鼎的capcom.sys(Htsysm72FB)驱动任意读写内核也是crackproof的《杰作》,允许任何进程运行带有未认证IOCTL的内核模式shellcode,内核里面还敢这样玩也是无敌了

1 个帖子 - 1 位参与者