原文:https://www.pediy.com/kssd/pediy10/68294.html
.text:00401A30 598 EB 05 jmp short loc_401A37 .text:00401A32 ; --------------------------------------------------------------------------- .text:00401A32 .text:00401A32 loc_401A32: ; CODE XREF: sub_4019F0:loc_401A37 p .text:00401A32 000 F9 stc ;表示借位 .text:00401A33 000 73 01 jnb short near ptr byte_401A36 ;不会跳转 .text:00401A35 000 C3 retn .text:00401A35 ; --------------------------------------------------------------------------- .text:00401A36 000 FF byte_401A36 db 0FFh ; CODE XREF: sub_4019F0+43 j .text:00401A37 ; --------------------------------------------------------------------------- .text:00401A37 .text:00401A37 loc_401A37: ; CODE XREF: sub_4019F0+40 j .text:00401A37 598 E8 F6 FF FF FF call loc_401A32 通过查看机器码,即可得到 eb 05 f9 73 01 c3 ff e8 f6 ff ff ff ==> 90 90 90 90 90 90 90 90 90 90 90 90
.text:00401BD2 070 mov eax, [ebp+arg_0] .text:00401BD5 070 sub eax, 10h .text:00401BD8 070 mov [ebp+var_14], eax .text:00401BDB 070 mov ecx, [ebp+var_14] .text:00401BDE 070 mov dword ptr [ecx], offset sub_4017F0 其函数中有两处验证,一处直接出错退出,另一处就是修改返回地址为出错函数处理的地址 .text:00401C54 070 mov ecx, [ebp+var_14] .text:00401C57 070 mov dword ptr [ecx], offset sub_4017B0 .text:00401C29 070 call sub_4017B0
v5 = "ABCDEFGHIJKLMNOPQRSTUVWXY"; v6 = "ABCDEFGHIJKLMNOPQRSTUVWXY"; // 转换字符串 v7 = 0; while ( v7 != 24 ) { if ( g_name == *v5 + 32 || byte_40416B[strlen(&g_name)] == *v5 + 32 ) ++v5; v8[v7++] = *v5; // 用户名转换后的数组,后面与注册码进行验证 v5 += 2; if ( !*v5 ) { if ( v7 < 24 ) v5 = v6 + 1; } }
v7 = 0; v10 = 5; v11 = 0; while ( v7 != 12 ) // 注册码进行验证 { v12 = 4 * v10 - 4; do { v0 = g_code[v7]; v4 = v8[v12++]; // 用户名转换后的数组 if ( v0 == v4 ) break; ++v11; } while ( v11 <= 4 ); // 用户名转换后的有五次碰撞机会. 我生成注册码时也就通过这个来完成的,对这个转换方法不太了解 if ( v11 == 5 ) { v13 = "ABCDEFGHIJKLMN"; // 迷惑人的 v14 = "OPQRSTUVWXYZ"; v11 = v0; if ( v0 > 0 ) sub_4017B0(); sub_4017B0(); // 出错提示后退出 } v7 += 2; --v10; if ( !v10 ) v10 = 6; v11 = 0; }
//.text:00401CC0 int __fastcall subOnOK(int a1) { int result; // eax@2 int v2; // ST08_4@1 int v3; // eax@1 int v4; // eax@1 int v5; // eax@1 int v6; // eax@1 int v7; // eax@1 int v8; // [sp+5Ch] [bp-4h]@1 char *code; // [sp+58h] [bp-8h]@1 char *name; // [sp+54h] [bp-Ch]@1 signed int v11; // [sp+50h] [bp-10h]@5 int v12; // [sp+0h] [bp-60h]@12 int *v13; // [sp+4Ch] [bp-14h]@12 v8 = a1; v2 = a1 + 96; v3 = CWnd__GetDlgItem(1001); CWnd__GetWindowTextA(v3, v2); v4 = sub_401E20(); code = (char *)CString__GetBuffer(v8 + 96, v4); v5 = CWnd__GetDlgItem(1002); CWnd__GetWindowTextA(v5, v8 + 100); v6 = sub_401E20(); v7 = CString__GetBuffer(v8 + 100, v6); name = (char *)v7; if ( strlen((const char *)v7) ) { if ( strlen(code) ) { v11 = 0; while ( name[v11] && name[v11] > 'a' && name[v11] < 'z' ) //用户名字符一定在['b'-'y']区间内 ++v11; if ( v11 == 6 ) //用户名长度必须为6个字符 { strcpy(&g_name, name); strcpy(g_code, code); v13 = &v12; result = sub_401BB0(&v12, name, code); } else { result = CWnd__MessageBoxA(v8, "非法用户!", 0, 0); } } else { result = CWnd__MessageBoxA(v8, "请输入注册码!", 0, 0); } } else { result = CWnd__MessageBoxA(v8, "请输入用户名!", 0, 0); } return result; } int __usercall sub_401BB0<eax>(int a1<eax>, int a2, int name, int code) // 注意通过第一个参数可以修改函数的返回地址 { int result; // eax@1 signed int v5; // [sp+68h] [bp-4h]@1 int (*v6)(); // [sp+64h] [bp-8h]@1 int v7; // [sp+60h] [bp-Ch]@1 int v8; // [sp+0h] [bp-6Ch]@1 int *v9; // [sp+5Ch] [bp-10h]@1 int v10; // [sp+58h] [bp-14h]@1 signed int v11; // [sp+54h] [bp-18h]@1 int v12; // [sp+50h] [bp-1Ch]@1 v5 = -1; v6 = SEH_401BB0; v7 = a1; v9 = &v8; result = a2 - 16; v10 = a2 - 16; *(_DWORD *)(a2 - 16) = sub_4017F0; // 函数返回地址 正确通过 v11 = 0; v12 = 0; while ( v11 < 6 ) { if ( *(_BYTE *)(v11 + name) != *(_BYTE *)(v12 + code) + 27 ) // 用户名的字符与注册码的关系1 sub_4017B0(); // 直接错误提示退出 if ( *(_BYTE *)(v11 + name) > *(_BYTE *)(v12 + code + 1) + 32 ) // 用户名的字符与注册码的关系2 *(_DWORD *)v10 = sub_4017B0; // 函数返回地址 错误提示退出 v12 += 2; result = v11++ + 1; } v29c = 6; // 觖发异常 执行sub_4019F0()函数 return result; } int __cdecl sub_4017F0() // 核心验证 { signed int v0; // eax@15 int v2; // eax@10 HANDLE v3; // eax@11 signed int v4; // edx@15 char *v5; // [sp+88h] [bp-4h]@1 char *v6; // [sp+84h] [bp-8h]@1 signed int v7; // [sp+64h] [bp-28h]@1 _BYTE v8[28]; // [sp+68h] [bp-24h]@6 HANDLE hProcess; // [sp+60h] [bp-2Ch]@11 signed int v10; // [sp+5Ch] [bp-30h]@12 signed int v11; // [sp+58h] [bp-34h]@12 int v12; // [sp+54h] [bp-38h]@14 char *v13; // [sp+50h] [bp-3Ch]@20 char *v14; // [sp+4Ch] [bp-40h]@20 v5 = "ABCDEFGHIJKLMNOPQRSTUVWXY"; v6 = "ABCDEFGHIJKLMNOPQRSTUVWXY"; // 转换字符串 v7 = 0; while ( v7 != 24 ) { if ( g_name == *v5 + 32 || byte_40416B[strlen(&g_name)] == *v5 + 32 ) ++v5; v8[v7++] = *v5; // 用户名转换后的数组,后面与注册码进行验证 v5 += 2; if ( !*v5 ) { if ( v7 < 24 ) v5 = v6 + 1; } } v2 = MessageBoxA((HWND)(g_code[10] == 85), "继续努力!", "错了!", 0); // 容易困惑的地方 注意注册码的第11个元素 v7 = v2; if ( v2 ) { v3 = GetCurrentProcess(); hProcess = v3; TerminateProcess(v3, 0); } v7 = 0; v10 = 5; v11 = 0; while ( v7 != 12 ) // 注册码进行验证 { v12 = 4 * v10 - 4; do { v0 = g_code[v7]; v4 = v8[v12++]; // 用户名转换后的数组 if ( v0 == v4 ) break; ++v11; } while ( v11 <= 4 ); // 用户名转换后的有五次碰撞机会. 我生成注册码时也就通过这个来完成的,对这个转换方法不太了解 if ( v11 == 5 ) { v13 = "ABCDEFGHIJKLMN"; // 迷惑人的 v14 = "OPQRSTUVWXYZ"; v11 = v0; if ( v0 > 0 ) sub_4017B0(); sub_4017B0(); // 出错提示后退出 } v7 += 2; --v10; if ( !v10 ) v10 = 6; v11 = 0; } return sub_401770(); } BOOL __cdecl sub_401770() { HANDLE v1; // eax@1 MessageBoxA(0, "过关!", "恭喜!", 0); v1 = GetCurrentProcess(); return TerminateProcess(v1, 0); } BOOL __cdecl sub_4017B0() { HANDLE v1; // eax@1 MessageBoxA(0, "继续努力!", "错了!", 0); v1 = GetCurrentProcess(); return TerminateProcess(v1, 0); } BOOL __cdecl sub_4019F0() // sub_401BB0()中的异常处理时 防动态调试的保护 { BOOL result; // eax@15 HANDLE v1; // eax@1 BOOL v2; // eax@1 HANDLE v3; // eax@2 BOOL v4; // eax@11 HANDLE v5; // eax@13 HANDLE v6; // [sp+468h] [bp-12Ch]@1 DWORD v7; // [sp+45Ch] [bp-138h]@1 DWORD v8; // [sp+460h] [bp-134h]@1 char Dst; // [sp+58h] [bp-53Ch]@1 HANDLE hSnapshot; // [sp+464h] [bp-130h]@1 PROCESSENTRY32 pe; // [sp+46Ch] [bp-128h]@1 BOOL v12; // [sp+458h] [bp-13Ch]@1 HANDLE hProcess; // [sp+54h] [bp-540h]@2 int v14; // [sp+50h] [bp-544h]@3 HANDLE v15; // [sp+4Ch] [bp-548h]@13 v6 = 0; v7 = 0; v8 = 0; memset(&Dst, 0, 0x400u); v1 = CreateToolhelp32Snapshot(0xFu, 0); hSnapshot = v1; pe.dwSize = 296; v2 = Process32First(v1, &pe); v12 = v2; if ( !v2 ) { v3 = GetCurrentProcess(); hProcess = v3; TerminateProcess(v3, 0); } v14 = 0; while ( v12 && !v7 && !v8 ) { if ( pe.th32ProcessID == GetCurrentProcessId() ) { v8 = pe.th32ParentProcessID; // 当前的父进程ID v6 = OpenProcess(0x1F0FFFu, 1, pe.th32ParentProcessID); } else { if ( !strcmp(pe.szExeFile, "explorer.exe") ) v7 = pe.th32ProcessID; // Explorer的 ID } v4 = Process32Next(hSnapshot, &pe); v12 = v4; if ( !v4 ) { if ( !v14 ) { v5 = GetCurrentProcess(); v15 = v5; TerminateProcess(v5, 0); } } ++v14; } result = v8; if ( v8 != v7 ) // 当前的父进程不为Explorer,直接挂了 result = TerminateProcess(v6, 0); return result; }
/* Dev-cpp 4.9.9.2 下编译通过 */ #include <windows.h> #include <stdio.h> #include <string.h> #include <time.h> /* 生成随机用户名 */ void GenUserName(char*username) { srand(time(NULL)); for(int i=0; i<5; i++) { username[i]='b'+rand()%('z'-'b'); } username[5]='p'; } void GenCheck(char *username, char *v8, char *v6) { char*v5=v6; int v7 = 0; while ( v7 != 24 ) { if ( username[0] == *v5 + 32 || username[strlen(username)-1] == *v5 + 32 ) ++v5; v8[v7++] = *v5; v5 += 2; if ( !*v5 ) { if ( v7 < 24 ) v5 = v6 + 1; } } } void GenKey(char *username, char *key) { for(int i=0; i<6; i++) { key[i*2]=username[i]-27; key[i*2+1]=username[i]-(rand()%32); } } int CheckKey(char *username, char *key, char *v8) { int v7 = 0; int v10 = 5; int v11 = 0; while ( v7 != 12 ) { int v12 = 4 * v10 - 4; do { BYTE v0 = key[v7]; BYTE v4 = v8[v12++]; if ( v0 == v4 ) break; ++v11; } while ( v11 <= 4 ); if ( v11 == 5 ) { username[v7>>1]=v8[v12-1-rand()%5]+27; if(!(username[v7>>1]>'a' && username[v7>>1]<'z')) for(int i=0; i<5; i++) { username[v7>>1]=v8[v12-1-i]+27; if((username[v7>>1]>'a' && username[v7>>1]<'z')) break; } return v7; } v7 += 2; --v10; if ( !v10 ) v10 = 6; v11 = 0; } return -1; } int main(void) { char username[256]=""; char key[512]=""; bool b=true; GenUserName(username); char v8[28]={0}; char*v6 = "ABCDEFGHIJKLMNOPQRSTUVWXY\0"; do { GenCheck(username, v8, v6); GenKey(username, key); } while(CheckKey(username, key, v8)>=0); printf("UserName: %s\n", username); printf("Key: %s\n", key); system("pause"); }