验证逻辑:
if ( (signed __int64)v5 <= 96000 && (signed __int64)v5 >= 90000 )
{
...
dwIoControlCode = 0x222041;
...
v7 = DeviceIoControl(hDevice, dwIoControlCode, &InBuffer, 0x107u, &OutBuffer, 0x400u, &BytesReturned, 0i64);
if ( !v7 )
{
MessageBoxW(0i64, L"wrong!", L"err", 0);
return 0i64;
}
}
输入数SN的范围在90000~96000之间,通过DeviceIoControl与驱动交互
InBuffer:
F0 F8 2C 00 00 00 00 00 //
50 20 99 3F 01 00 00 00 //
E0 1F 00 00 00 00 00 00 //pid
62 64 01 00 00 00 00 00 //SN
EB 18 //一段可执行代码
00 00 00 00 00 00 00 00
08 00 00 00 00 00 00 00
60 6B 99 3F 01 00 00 00 //
55 48 8B EC E8 01 00 00 00 90 48 8B C4 48 C7 C1 10 00 00 00 48 33 D2 48 F7 F1 83 FA 00 75 17 48
8B 04 24 48 89 44 24 F8 48 8B 44 24 08 48 89 04 24 48 8D 64 24 F8 48 8B 0C 24 48 8B 51 DF 48 83
FA 00 74 04 48 89 55 08 48 8B 51 E7 48 83 FA 00 48 BA 2D 7F 6C 43 F6 7F 00 00 48 B8 CE 7F 6C 43
F6 7F 00 00 9C 48 2B C2 9D 74 17 48 8D 51 DD 48 8D 14 10 48 8B 41 E7 48 8D 04 10 48 8B 49 EF 51
FF D0 48 8B E5 5D C3
00 00 00 00
E8 59 0D 6D 80 3C A2 78 15 87 16 16 07 26 68 55 7F 12 F1 EF F9 A1 9C E8 EA 9C 90 F4 9F 3A A8 8C //一段密文
27 47 79 F6 DC 20 7F 86 ED 34 7E F7 1C 55 6B F6 EF F2 2A 7A F0 44 50 8A 9B E1 C4 E1 45 90 2B 0E
CF AF
再到驱动里看一看:
PAGE:00000001400050A6 cmp dword ptr [rax+18h], 222041h
PAGE:00000001400050AD mov r13d, [rax+10h]
PAGE:00000001400050B1 jnz loc_14000514E
PAGE:00000001400050B7 mov rcx, [rdx+8]
PAGE:00000001400050BB mov r15, [rdx+18h] //InBuffer
PAGE:00000001400050BF test byte ptr [rcx+0Ah], 5
PAGE:00000001400050C3 jz short loc_1400050CB
PAGE:00000001400050C5 mov r12, [rcx+18h]
PAGE:00000001400050C9 jmp short loc_1400050EA
...
PAGE:00000001400050EA loc_1400050EA: mov rax, [r15]
PAGE:00000001400050ED mov r14, [r15+8]
PAGE:00000001400050F1 mov rdi, [r15+18h] //SN
PAGE:00000001400050F5 mov [rsp+58h+arg_8], rax
PAGE:00000001400050FA call sub_14000110D //获取一段shellcode长度 = 0xA1
PAGE:00000001400050FF movsxd rbx, eax
PAGE:0000000140005102 mov esi, r13d //InBuffer总长度 = 0x107
PAGE:0000000140005105 mov r8d, edi //SN作为解密key
PAGE:0000000140005108 lea ecx, [rax+24h]
PAGE:000000014000510B sub esi, ecx //密文长度0x107 - 0xA1 - 0x24 = 0x42
PAGE:000000014000510D lea rcx, [r15+24h]
PAGE:0000000140005111 add rcx, rbx //密文指针
PAGE:0000000140005114 mov edx, esi //密文长度
PAGE:0000000140005116 call sub_1400015A0 //解密算法
PAGE:000000014000511B cmp [rbx+r15+24h], esi //如果解密出的数据第一个DWORD等长度0x42,就OK了
PAGE:0000000140005120 jnz short loc_140005139
所以把sub_1400015A0扔进ida里F5一下,写个穷举程序就得到了SN=91024
穷举代码:
#include <windows.h> #include <stdio.h> #include <math.h> void decode(BYTE *a1, int len, int key) { void **v3; // rax int v4; // er10 __int64 v5; // rbx int v6; // esi __int64 v7; // r11 unsigned __int8 v8; // al __int64 v9; // r8 __int16 v10; // di unsigned __int16 v11; // dx void *retaddr; // [rsp+0h] [rbp+0h] v3 = &retaddr; v4 = key - 1; v5 = len; if ( key - 1 >= 0 ) { v6 = len - 1; do { v7 = v4 % (signed int)v5; if ( v4 % (signed int)v5 ) { v8 = a1[v7 - 1]; v9 = v4 % (signed int)v5; } else { v8 = a1[v5 - 1]; v9 = 0i64; } if ( (DWORD)v7 == v6 ) v10 = (unsigned __int8)*a1 + ((unsigned __int8)a1[v9] << 8); else v10 = *(WORD *)&a1[v9]; v11 = v10 + v8; *(WORD *)v3 = v11 >> 8; a1[v9] = HIBYTE(v11); if ( (DWORD)v7 == v6 ) *a1 = v11; else a1[v9 + 1] = v11; --v4; } while ( v4 >= 0 ); } } BYTE data[] = { 0xE8,0x59,0x0D,0x6D,0x80,0x3C,0xA2,0x78,0x15,0x87,0x16,0x16,0x07,0x26,0x68,0x55, 0x7F,0x12,0xF1,0xEF,0xF9,0xA1,0x9C,0xE8,0xEA,0x9C,0x90,0xF4,0x9F,0x3A,0xA8,0x8C, 0x27,0x47,0x79,0xF6,0xDC,0x20,0x7F,0x86,0xED,0x34,0x7E,0xF7,0x1C,0x55,0x6B,0xF6, 0xEF,0xF2,0x2A,0x7A,0xF0,0x44,0x50,0x8A,0x9B,0xE1,0xC4,0xE1,0x45,0x90,0x2B,0x0E, 0xCF,0xAF }; void crack04() { BYTE t[0x100]; int i; for (i=90000;i<96000;i++) { memcpy(t,data,sizeof(data)); decode(t,sizeof(data),i); if (*(DWORD *)t == 0x42) { printf("%d",i); } } } int main(int argc, char* argv[]) { crack04(); getchar(); return 1; }