直接贴上答案中提供的文档,如下(别人博客中文章编辑得十分漂亮,各种高亮,但这个对我来说太难了。。):
运行“破解考题.exe”后,使用远程注入工具“RemoteDll.exe”将“patch.dll”注入到进程“破解考题.exe”,之后即可使用“keygen.exe”生成注册码进行注册。
如:
MyNameIsMrWrong
6B707743323168447730652B5A68315639572F74566E75564D3251364F48305432522B6F4441697848334F766749494E5846365249575647363873326A516A756F326B62
MrWrong
45784F625156694C304D70355A68315639572F74566E75564D3251364F48305432522B6F4441697848334F766749494E5846365249575647363873326A516A756F326B62
代码开发环境:win7 x64 sp1
程序不完全分析如下:1.首先脱掉压缩壳便于分析。
2.脱壳后分析发现,有如下代码:
if ( CreateMutexW(0, 0, Name) )
{
if ( GetLastError() == 0xB7 )
{
CreateThread(0, 0, sub_401BC0, 0, 0, 0); //创建线程,线程内还会创建线程,解密用于校验的部分代码,
}
else //是第一个实例,则以调试方式运行自己的副本
{
Filename = 0;
memset(&v10, 0, 0x206u);
memset(&StartupInfo.lpReserved, 0, 0x40u);
StartupInfo.cb = 68;
GetModuleFileNameW(0, &Filename, 0x208u);
if ( CreateProcessW(&Filename, 0, 0, 0, 0, 1u, 0, 0, &StartupInfo, &ProcessInformation) )
{
DebugEvent.dwDebugEventCode = 0;
memset(&DebugEvent.dwProcessId, 0, 0x5Cu);
while ( WaitForDebugEvent(&DebugEvent, 0xFFFFFFFF) )
{
if ( DebugEvent.dwDebugEventCode == 8 ) //单步调试副本,直到副本output一个DebugString
break;
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, 0x10002u);
}
DebugSetProcessKillOnExit(0);
DebugActiveProcessStop(ProcessInformation.dwProcessId);
ExitProcess(0);
}
}
}
3.用于校验的部分代码是通过文件的crc32校验以及哈希值加密的,如果改变文件则无法正确解密。正确解密后通过与地址00541702处 call VirtualProtect,修改此段动态申请内存为PAGE_EXECUTE_READWRITE
权限。我并不打算在这之前修改程序中的任何数据,所以这一块东西并不担心,就此打住。
4.解密出来的这部分代码分析(注册码校验过程):
(1)注册码全是数字,两两组合后为一段字符串,记为”A“,对A进行base64解密(base64解密函数为相对于这块动态申请的内存偏移为0x1000,记为sub_off_1000),base64解密后,得到的数据记为”B“。
(2)”B”将通过函数sub_off_1A90解密得到"C",内部固定使用秘钥"lingdux_keygen",是512位的加解密方式,但此解密函数我未弄明白是什么算法,仅怀疑是AES512,(固不下钩子的注册机无法给出)。
(3)计算Username字符串的MD5值,记为“D”。
(4)对于“C”,需满足如下关系。
C[0] == D[0];
C[1] == D[2];
C[2] == D[4];
C[3] == D[6];
C[5] == D[8];
C[6] == D[10];
C[7] == D[12];
C[8] == D[14];
(5)使用函数sub_off_1DD0+秘钥“lingdux”,解密一串二进制(为弄明白的二进制串,记为”Q“),得到固定字符串:”Success“,由于sub_off_1A90函数未弄明白,写出注册机的想法心灰意冷,并且上班工作繁忙,这里就不管他了。
但是这个"Q"肯定是由”C“的后面部分变形而来。
(6)计算字符串”Success“的MD5值,得到二进制序列: 505a83f220c02df2f85c3810cd9ceb38,并与程序中存储的二进制序列比较。如果不是则功亏一篑。
注册机无法做出,就将没弄明白的地方HOOK住,变成已知的。
如下:
int __stdcall hook_off_1a90(void)
{
BYTE* p; //[in] & [out]
_asm
{
mov p, ecx
}
//做注册机时,可对p中的数据进行加密,我没有进行加密了,直接原封不动。
// some_encrypt(p,64);
return 1;
}
还有一处hook,是为了hook_off_1a90的时机,即在即将调用上文中”校验的部分代码“时。
00401A20 ; DWORD __stdcall sub_401A20(LPVOID lpThreadParameter)
00401A20 lpThreadParameter= dword ptr 4
00401A20
00401A20 push offset dword_5B40A8
00401A25 call dword_5B40A0 //此处下刀
00401A2B add esp, 4
00401A2E xor eax, eax
00401A30 retn 4
00401A30 StartAddress endp
钩子源码部分如下:
int __stdcall hook_5b40a0(int np)
{
_asm
{
pushad
pushfd
}
static BOOL patched = FALSE;
if(!patched)
{
patched = TRUE;
DWORD addr = (DWORD)g_5b40a0 - 0x1F20 + 0x2167 + 1;
DWORD call_offset = (DWORD)hook_off_1a90 - addr - 4;
*(DWORD*)addr = call_offset; //hooked hook_off_1a90
}
_asm
{
popfd
popad
}
int ret = g_5b40a0(np);
return ret;
}
其它部分和原注册算法一致,仅在未知之处略施手段,变未知为已知。
时间有限,远程注入工具则使用一款经典的工具”RemoteDll.exe“。
学海无涯,失误之处敬请谅解。
by:MrWrong 邮箱:[email protected] 20140428
文件: http://files.cnblogs.com/MrWrong/360.rar