来源:自学PHP网 时间:2015-04-17 13:03 作者: 阅读:次
[导读] 作 者: uuk【软件名称】: Total Commander【软件版本】: 7.56a【加壳方式】: 新版不加壳【编写语言】: Borland Delphi 2.0 [Overlay]【使用工具】: OD PEID IDA【操作平台】: Windows XP【软件介......
作 者: uuk
【软件名称】: Total Commander 【软件版本】: 7.56a 【加壳方式】: 新版不加壳 【编写语言】: Borland Delphi 2.0 [Overlay] 【使用工具】: OD PEID IDA 【操作平台】: Windows XP 【软件介绍】: 一款挺不错的双栏文件管理软件 【作者声明】: 只是研究用,使用请购买正版 我们知道Total Commander是有自校验的,通过跟踪CreateFile和ReadFile函数,确定校验过程是在函数sub_47823C中进行的。 代码: 0047823C push ebp ; 自校验函数 0047823D mov ebp, esp 0047823F add esp, -824 00478245 mov dword ptr [ebp-4], -1 ; 初始化校验和为CHECKSUM=-1 0047824C lea eax, dword ptr [ebp-814] 00478252 mov dword ptr [ebp-18], eax 00478255 lea eax, dword ptr [ebp-824] 0047825B mov edx, 3FF 00478260 call 006BE3AC ; GetModuleFileName() 00478265 lea edx, dword ptr [ebp-1C] 00478268 mov eax, dword ptr [6C7D58] 0047826D mov ecx, 4 00478272 call 004027B4 00478277 mov eax, 8001 0047827C call 00402684 ; AllocateMem() 00478281 mov dword ptr [ebp-C], eax 00478284 lea eax, dword ptr [ebp-824] 0047828A mov ecx, 1 0047828F xor edx, edx 00478291 call 0041D70C ; CreateFile() 00478296 mov dword ptr [ebp-10], eax 00478299 call 004035AC 0047829E cmp dword ptr [eax+C], 0 004782A5 je short 004782BF 上面是函数的初始化。 代码: 004782F7 xor eax, eax 004782F9 mov dword ptr [ebp-24], eax 004782FC mov eax, dword ptr [ebp-10] 004782FF call 00419874 ; 计算文件大小 00478304 sub eax, 18 00478307 sub eax, 0C ; 文件大小减去36字节 0047830A mov dword ptr [ebp-20], eax 0047830D cmp dword ptr [ebp-20], 8000 00478314 jle short 0047831E 00478316 mov word ptr [ebp-12], 8000 0047831C jmp short 00478326 0047831E mov ax, word ptr [ebp-20] 00478322 mov word ptr [ebp-12], ax 00478326 lea eax, dword ptr [ebp-14] 00478329 push eax 0047832A mov edx, dword ptr [ebp-C] 0047832D mov cx, word ptr [ebp-12] 00478331 mov eax, dword ptr [ebp-10] 00478334 call 0041DE4C ; ReadFile():从文件中读取0x8000大小的数据块 00478339 cmp dword ptr [ebp-24], 0 0047833D jnz short 0047834A 0047833F lea edx, dword ptr [ebp-20] 00478342 mov eax, dword ptr [ebp-C] 00478345 call 00478054 ; 首次计算校验和前先清除Checksum和数字签名,并计算要校验的数据大小 0047834A lea ecx, dword ptr [ebp-4] 0047834D movzx edx, word ptr [ebp-14] 00478351 mov eax, dword ptr [ebp-C] 00478354 call 0067FF10 ; 分块分片计算校验和 00478359 movzx eax, word ptr [ebp-14] 0047835D sub dword ptr [ebp-20], eax 00478360 movzx eax, word ptr [ebp-14] 00478364 add dword ptr [ebp-24], eax 00478367 movzx eax, word ptr [ebp-14] 0047836B cmp eax, 8000 00478370 jnz short 00478378 00478372 cmp dword ptr [ebp-20], 0 00478376 jnz short 0047830D 00478378 mov edx, 8001 0047837D mov eax, dword ptr [ebp-C] 00478380 call 0040269C ; FreeMem() 00478385 lea eax, dword ptr [ebp-14] 00478388 push eax 00478389 lea edx, dword ptr [ebp-824] 0047838F mov cx, 24 00478393 mov eax, dword ptr [ebp-10] 00478396 call 0041DE4C ; 读取最后36的字节,校验和存储在第16~20字节里面 0047839B mov eax, dword ptr [ebp-10] 0047839E call 0041DDE4 ; CloseHandle() 004783A3 mov eax, dword ptr [ebp-18] 004783A6 mov eax, dword ptr [eax] 004783A8 xor eax, 2A67BE65 ; 对存储的校验和进行异或 004783AD mov dword ptr [ebp-8], eax 004783B0 push ebp 004783B1 call 004781E4 ; 比较异或后的两个校验和,并利用两个校验和计算其它数据 至此完成了校验和的计算和比较。 sub_0067FF10函数的反汇编代码如下: 代码: 0067FF10 push ebx 0067FF11 push esi 0067FF12 push edi 0067FF13 add esp, -0C 0067FF16 mov dword ptr [esp+4], ecx 0067FF1A mov dword ptr [esp], edx 0067FF1D mov ecx, eax 0067FF1F mov ebx, dword ptr [esp+4] 0067FF23 mov ebx, dword ptr [ebx] 0067FF25 and ebx, 0FFFF ; 取上次校验和的低16位给LOW 0067FF2B mov esi, dword ptr [esp+4] 0067FF2F mov esi, dword ptr [esi] 0067FF31 shr esi, 10 0067FF34 and esi, 0FFFF ; 取上次校验和的高16位给HIGH 0067FF3A test ecx, ecx 0067FF3C jnz short 0067FF4A 0067FF3E mov eax, dword ptr [esp+4] 0067FF42 mov dword ptr [eax], 1 0067FF48 jmp short 0067FFB8 0067FF4A cmp dword ptr [esp], 0 0067FF4E jle short 0067FFAD 0067FF50 cmp dword ptr [esp], 15B0 ; 分成0x15B0大小的数据来计算 0067FF57 jge short 0067FF62 0067FF59 mov eax, dword ptr [esp] 0067FF5C mov dword ptr [esp+8], eax 0067FF60 jmp short 0067FF6A 0067FF62 mov dword ptr [esp+8], 15B0 0067FF6A mov eax, dword ptr [esp+8] 0067FF6E sub dword ptr [esp], eax 0067FF71 mov eax, dword ptr [esp+8] 0067FF75 dec eax 0067FF76 test eax, eax 0067FF78 jb short 0067FF89 0067FF7A inc eax 0067FF7B xor edx, edx 0067FF7D movzx edi, byte ptr [ecx+edx] ; 每次取一个字节,循环计算 0067FF81 add ebx, edi 0067FF83 add esi, ebx 0067FF85 inc edx 0067FF86 dec eax 0067FF87 jnz short 0067FF7D 0067FF89 mov eax, dword ptr [esp+8] 0067FF8D add ecx, eax 0067FF8F mov eax, ebx 0067FF91 mov ebx, 0FFF1 0067FF96 cdq 0067FF97 idiv ebx ; 将LOW对0xFFF1取模,结果给CHECKSUM的低16位 0067FF99 mov ebx, edx 0067FF9B mov eax, esi 0067FF9D mov esi, 0FFF1 0067FFA2 cdq 0067FFA3 idiv esi ; 将HIGH对0xFFF1取模,结果给CHECKSUM的高16位 0067FFA5 mov esi, edx 0067FFA7 cmp dword ptr [esp], 0 0067FFAB jg short 0067FF50 0067FFAD shl esi, 10 0067FFB0 or ebx, esi 0067FFB2 mov eax, dword ptr [esp+4] 0067FFB6 mov dword ptr [eax], ebx 0067FFB8 add esp, 0C 0067FFBB pop edi 0067FFBC pop esi 0067FFBD pop ebx 0067FFBE retn 自校验的C语言代码如下: 代码: // Totalcmd_FixCRC.cpp : 自校验 #include "stdafx.h" // 使用说明 void Usage(); // 计算校验和 void CalculateCRC(unsigned char * pData, unsigned int nSize, unsigned int * nCRC); // 修复数据及其大小 void FixData(char * pData, unsigned int * nSize); int _tmain(int argc, _TCHAR* argv[]) { TCHAR * szFileName = NULL; char lpBuffer[0x8001] = {0}; unsigned int nNumberOfBytesToRead = 0; unsigned int nNumberOfBytesRead = 0; unsigned int nSize = 0; unsigned int nSizeRead = 0; unsigned int nCRC = 0xffffffff; HANDLE hFile = NULL; printf("\nTotalcmd_FixCRC by uuk 2012.03.23\n\n"); if ( argc != 2 ) { Usage(); return 0; } szFileName = argv[1]; hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if ( hFile == INVALID_HANDLE_VALUE ) { printf("CreateFile Error!\n"); return 1; } nSize = SetFilePointer(hFile, 0, NULL, FILE_END); if ( nSize == INVALID_SET_FILE_POINTER) { printf("SetFilePointer Error!\n"); CloseHandle(hFile); return 2; } nSize -= 36; SetFilePointer(hFile, 0, NULL, FILE_BEGIN); do { if ( nSize >= 0x8000 ) nNumberOfBytesToRead = 0x8000; else nNumberOfBytesToRead = nSize; ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, (LPDWORD)&nNumberOfBytesRead, NULL); if ( nSizeRead == 0 ) FixData(lpBuffer, &nSize); CalculateCRC((unsigned char *)lpBuffer, nNumberOfBytesRead, &nCRC); nSizeRead += nNumberOfBytesRead; nSize -= nNumberOfBytesRead; } while ( (nNumberOfBytesRead==0x8000) && nSize ); // 读取文件中存储的校验和 ReadFile(hFile, lpBuffer, 36, (LPDWORD)&nNumberOfBytesRead, NULL); unsigned int nCRC2 = *(unsigned int *)(lpBuffer+0x10); nCRC = nCRC ^ 0xF5A3E289; nCRC2 = nCRC2 ^ 0x2A67BE65; if ( nCRC != nCRC2 ) { unsigned int nCRC3 = nCRC ^ 0x2A67BE65; SetFilePointer(hFile, nSizeRead+0x10, NULL, FILE_BEGIN); int nWrite = 0; WriteFile(hFile, &nCRC3, 4, (LPDWORD)&nWrite, NULL); printf("File is Fixed!\n"); } else { printf("File is not modified!\n"); } CloseHandle(hFile); return 0; } void Usage() { printf("Usage: Totalcmd_FixCRC.exe FileName\n"); } void CalculateCRC(unsigned char * pData, unsigned int nSize, unsigned int * nCRC) { unsigned int nSizeRead; int nCRCLow, nCRCHigh; nCRCLow = *nCRC & 0xffff; nCRCHigh = (*nCRC>>16) & 0xffff; if ( pData ) { if ( nSize > 0 ) { do { if ( nSize >= 5552 ) nSizeRead = 5552; else nSizeRead = nSize; nSize -= nSizeRead; do { nCRCLow += *pData; nCRCHigh += nCRCLow; pData++; nSizeRead--; } while ( nSizeRead ); nCRCLow %= 65521; nCRCHigh %= 65521; } while ( nSize > 0 ); } *nCRC = ( nCRCHigh << 16 ) | nCRCLow; } else { *nCRC = 1; } } void FixData(char * pData, unsigned int * nSize) { int i = 0; if ( pData[0x198] != '\0' ) { *nSize = *(unsigned int *)(pData+0x198) - 36; for (i=0; i<8; i++) { pData[0x198+i] = '\0'; } } for (i=0; i<4; i++) { pData[0x158+i] = '\0'; } } 新程序采用的注册算法没有变,只是将网上公开的许可文件加入黑名单。黑名单中是许可文件的许可号(每个占4字节)。Totalcmd756a版本的黑名单如下所示: 004E0ABC Totalcmd mov eax, 006C8A3C ; 黑名单1 004E0AD5 Totalcmd mov eax, 006C8BE0 ; 黑名单2 004E0AEB Totalcmd mov eax, 006C90F4 ; 黑名单3 004E0B07 Totalcmd mov eax, 006C9168 ; 黑名单4 比较有意思的是我们可以通过特殊的方法修改黑名单里面的数据而不改变校验和。推导CalculateCRC() 函数中校验和的计算公式得: (Bn代表第n个字节的值) 由于(n - 1) + (n+1) = 2n,所以根据校验码的计算公式可以将Bn-1和Bn+1的值各加1,然后将Bn值减2,则总结果不变。因此可以通过这个办法将许可证黑名单中的许可号改掉。如许可号#1283在黑名单中,其HEX值为0x00000503,在文件中是以0x03050000存储的,将其改成0x04030100则许可文件可继续使用,程序也不报错 |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com