直接贴上答案中提供的文档,以下(别人博客中文章编辑得十分漂亮,各类高亮,但这个对我来讲太难了。。):算法
运行“破解考题.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);
}
}
}orm
3.用于校验的部分代码是经过文件的crc32校验以及哈希值加密的,若是改变文件则没法正确解密。正确解密后经过与地址00541702处 call VirtualProtect,修改此段动态申请内存为PAGE_EXECUTE_READWRITE
权限。我并不打算在这以前修改程序中的任何数据,因此这一块东西并不担忧,就此打住。blog
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 邮箱:rongguozhen@foxmail.com 20140428
文件: http://files.cnblogs.com/MrWrong/360.rar