Tornado2之Licence暴力破解 (15千字)

看雪資料發表於2000-10-22

Tornado2之Licence暴力破解

Tornado2是VxWorks開發除錯工具,試用期為一個月.
超過試用期需要Licence支援,一個Licence需要$6000~$2000.買了軟體,還要花錢,真是!@#$%^&*.

破解如下,希望對大家有用. :)

1.跟蹤:
Tornado2的Licence程式主要執行在 ...\\host\\x86-win32\\bin\\tgtsvr.exe(...為Tornado2安裝目錄)

經過痛苦的跟蹤過程,發現008B5236處為判斷鑑權是否成功(該地址是在NT4.0+SP5.0中,可能系統
不一樣,地址會不一樣).跟蹤過程就不寫了吧.大家都是高手,我的跟蹤過程寫出來,大家會笑話的.
在跟蹤過程中,我犯了很多愚蠢的錯誤,甚至死了很多次.後來發現都是可以避免的.

008B5236前有一系列CALL,是進行計算的.我曾跟進去,但發現是可能一個DLL.該公司用一個DLL進行運
算,我是不能透過演算法破解了,只好暴力破解.

寫破解程式碼可能對大家有一些作用,我將詳細介紹.

2.破解思路:
該程式是透過加殼的,殼比較奇怪,我孤陋寡聞,沒有見過.
我的想法是,我也可以在程式中加外殼,先獲得控制修改程式碼,在原來殼結束時,作跳轉到我的修改程式碼.
原來程式入口是00426DF5,原來殼的結束位置是00426F33.
1)將程式的入口地址改為00400300
mov        ebx,426F33h
mov        dword ptr [ebx],0FD93C8E9h
add        ebx,4
mov        byte ptr [ebx],0FFh
jmp        00426DF5
//以上為將00426F33改為jmp 1111.
1111.為自己程式碼地址
push        ebx
mov        ebx,426F33h
mov        dword ptr [ebx],535BD0FFh
add        ebx,4
mov        byte ptr [ebx],81h
//以上為將00426F33改為
{
    00426F33 FF D0                call        eax
    00426F35 5B                  pop        ebx
    00426F36 53                  push        ebx
    00426F37 81 EB 2E 0D 00 00    sub        ebx,0D2Eh
}
mov        ebx,eax
add        ebx,0E10Ah
mov        dword ptr [ebx],7DEBC033h
//以上將程式改成鑑權成功
{
    008B5236 33 C0                xor        eax, eax
    008B5238 EB 7D                jmp        008B52B5
}
sub        ebx, 0B7h//ebx=008B517F
mov        word ptr [ebx],xxxx
//以上將程式改成98下跳到NT程式碼中執行
{
    008B517F jmp 008B51C5
}
pop        ebx
jmp        00426F33

外殼程式詳細說明:
1)改變程式的入口地址到自己程式碼,在自己程式碼地方寫跳轉程式碼.該跳轉程式碼將00426F33處程式改成jmp xxxx.
在該項操作中,需要取硬碟序列號,與jmp xxxx的機器碼做xor運算.
取硬碟序列號使用LoadLibrary,GetProcAddress和GetVolumeInformationA.
其中LoadLibrary和GetProcAddress的函式地址需要查原來程式地址.
    LoadLibrary = 00426FD0
    GetProcAddress = 00426FCA
    CALL xxxx = E8 + 偏移(4位)
2)在上面的jmp xxxx的xxxx地方處寫程式碼,改變程式的執行路徑.
需要有如下幾個具體操作:
(1)將00426F33處還原
(2)改程式為98下也到NT程式碼中執行
(3)該程式為鑑權成功
3)需要的固定資料:
'KERNEL32.DLL', 0 //13 BYTES,LoadLibraryA用
'GetVolumeInformationA', 0 //22 BYTES,GetProcAddress用
'C:\', 0 //4 BYTES, GetVolumeInformationA用
總共0x27 = 39個BYTE
因此資料從400300開始,程式碼從00400330開始.

外殼程式實現:
1)將幾個固定資料寫進檔案中:Raw Address = 0x300
00400300    'KERNEL32.DLL', 0
0040030D    'GetVolumeInformationA', 0
00400323    'C:\', 0
00400327    4 BYTE 資料
0040032B    0

2)寫跳轉程式碼,將00426F33處程式改成jmp xxxx, Raw Address = 0x330
00400330   
00400330 55                  push        ebp
00400331 8B EC                mov        ebp,esp
00400333 83 EC 30            sub        esp,70h  ;實際使用0x22 BYTE
00400336 68 00 03 40 00      push        400300h  ;'KERNEL32.DLL'
0040033B E8 90 6C 02 00      call        426FD0h;LoadLibraryA
00400341 68 0D 03 40 00      push        40030Dh  ;'GetVolumeInformationA'
00400346 50                  push        eax      ;hModule
00400347 E8 7F 6C 02 00      call        426FCAh;GetProcAddress
0040034B 6A 0A                push        0Ah      ;sizeof(lpFileSystemNameBuffer)
0040034D 8D 5D D8            lea        ebx,[ebp-28h]
00400350 53                  push        ebx
00400351 8D 5D D0            lea        ebx,[ebp-30h]
00400354 53                  push        ebx
00400355 8D 5D E4            lea        ebx,[ebp-1Ch]
00400358 53                  push        ebx
00400359 8D 5D E8            lea        ebx,[ebp-18h]
0040035C 53                  push        ebx
0040035D 6A 0C                push        0Ch
0040035F 8D 5D F0            lea        ebx,[ebp-10h]
00400362 53                  push        ebx
00400363 68 23 03 40 00      push        400323
00400368 FF D0                call        eax
0040036A 8B 45 E8            mov        eax,dword ptr [ebp-18h];VolumeSerialNumber
0040036D BB 27 03 40 00      mov        ebx,400327h
00400372 33 03                xor        eax,dword ptr [ebx]
00400374 BB 33 6F 42 00      mov        ebx,426F33h
00400379 89 03                mov        dword ptr [ebx],eax
0040037B 83 C3 04            add        ebx,4
0040037E C6 03 FF            mov        byte ptr [ebx],0FFh;原來是E9 54 94 FD FF jmp 0040038D
00400381 83 C4 70            add        esp,70h
00400384 8B E5                mov        esp,ebp
00400386 5D                  pop        ebp
00400387 E9 69 6A 02 00      jmp        00426DF5;跳轉程式碼完成
0040038C
0040038C 53                  push        ebx
0040038D BB 33 6F 42 00      mov        ebx,426F33h
00400392 C7 03 FF D0 5B 53    mov        dword ptr [ebx],535BD0FFh
00400398 83 C3 04            add        ebx,4
0040039B C6 03 81            mov        byte ptr [ebx],81h
0040039E 8B D8                mov        ebx,eax
004003A0 81 C3 0A E1 00 00    add        ebx,0E10Ah
004003A6 C7 03 33 C0 EB 7D    mov        dword ptr [ebx],7DEBC033h
004003AC 81 EB B7 00 00 00    sub        ebx,0B7h
004003B2 66 C7 03 EB 44      mov        word ptr [ebx],44EBh
004003B7 5B                  pop        ebx
004003B8 E9 76 6B 02 00      jmp        00426F33
004003BD

實驗資料:
VolumeSerialNumber = 0x283a1709
E9 54 94 FD ^ VolumeSerialNumber = 0xd5ae43e0

其中的GetVolumeInformationA和變化資料,不是必須的.在寫這一段程式碼時,不能將他放到原來的程式碼塊中,
我曾經放過,但程式執行死了.可能有其他檢查,但程式死的時候,堆疊已經被破壞了,我無法定位,不知哪位
能指點?

3.C程式碼
#include <windows.h>
#include <shlobj.h>
#include "resource.h"

#define OPEN_ERROR          -1
#define READ_ERROR          -2
#define WRITE_ERROR        -3
#define FILE_ERROR          -4
#define NO_KEY              -5

int WriteCrack(HANDLE hFile)
{
    DWORD dwWrited;
//1.寫入口
    SetFilePointer(hFile, 0xf0, 0, FILE_BEGIN);
    DWORD dwEntry = 0x330;
    WriteFile(hFile, &dwEntry, 4, &dwWrited, NULL);

//2.寫固定資料
    LPTSTR tt = MAKEINTRESOURCE(IDR_CRACKDATA1);
    HRSRC hRsrc = FindResource(GetModuleHandle(NULL),
        MAKEINTRESOURCE(IDR_CRACKDATA1), "CRACKDATA");
    HGLOBAL hGlobal = LoadResource(GetModuleHandle(NULL), hRsrc);
    LPVOID lpData = LockResource(hGlobal);
    SetFilePointer(hFile, 0x300, 0, FILE_BEGIN);
    WriteFile(hFile, lpData, 0xc0, &dwWrited, NULL);

//3.寫變化資料
    DWORD dwChangeData = 0xfd9454e9;//E9 54 94 FD
    BYTE lpRootPathName[4] = "c:\\"; //取C盤的序列號
    BYTE lpVolumeNameBuffer[12];//磁碟卷標
    DWORD nVolumeNameSize = 12;
    DWORD VolumeSerialNumber;//磁碟序列號
    DWORD MaximumComponentLength;
    BYTE lpFileSystemNameBuffer[10];
    DWORD nFileSystemNameSize=10;
    DWORD FileSystemFlags;
    GetVolumeInformation((char*)&lpRootPathName[0],
        (char*)&lpVolumeNameBuffer[0], nVolumeNameSize,
        &VolumeSerialNumber, &MaximumComponentLength,
        &FileSystemFlags,
        (char*)&lpFileSystemNameBuffer[0], nFileSystemNameSize);
    dwChangeData ^= VolumeSerialNumber;
    SetFilePointer(hFile, 0x327, 0, FILE_BEGIN);
    WriteFile(hFile, &dwChangeData, 4, &dwWrited, NULL);
    return 1;
}

int WriteCrackData(char* szFileName)
{
    HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if(hFile == INVALID_HANDLE_VALUE)
    {
        MessageBox(NULL, "Please quit TornadoII program!\r\n"
            "Ensure not any program lock TornadoII resource!", "Warnning", MB_OK | MB_ICONHAND);
        return OPEN_ERROR;
    }
//讀資料,判斷該檔案是否可寫
    SetFilePointer(hFile, 0xf0, 0, FILE_BEGIN);
    DWORD dwEntry;
    DWORD dwReaded;
    if(ReadFile(hFile, &dwEntry, 4, &dwReaded, NULL) == FALSE)
    {
        MessageBox(NULL, "Please quit TornadoII program!\r\n"
            "Ensure not any program lock TornadoII resource!", "Warnning", MB_OK | MB_ICONHAND);
        CloseHandle(hFile);
        return READ_ERROR;
    }
    if(dwEntry != 0x330)//自己寫的入口
    {
        if(dwEntry != 0x26df5)//原本的程式入口
        {
            if(MessageBox(NULL, "TornadoII maybe infected by virus!\r\nRun the patch maybe destroy TornadoII!\r\n"
                "If you want continue,press OK,CANCEL to quit!\r\nDo you want continue?", "Warnning", MB_OKCANCEL | MB_ICONHAND)
                == IDCANCEL)
                CloseHandle(hFile);
                return FILE_ERROR;
        }
    }
    WriteCrack(hFile);
    CloseHandle(hFile);
    return TRUE;
}

int WriteBack()
{
    HKEY hKey;
    if(RegOpenKey(HKEY_CURRENT_USER, "TNT TornadoII Patch1", &hKey)
        != ERROR_SUCCESS)
        return NO_KEY;

    char szFileName[255];
    memset(szFileName, 0, sizeof(char) * 255);
    long length = 255;
    DWORD FileAttribute = 0;
    BYTE FileTime[255];
    memset(FileTime, 0, sizeof(BYTE) * 255);
    DWORD dwLength;

    if(RegQueryValue(hKey, "Path", szFileName, &length)
        != ERROR_SUCCESS)
    {
        RegCloseKey(hKey);
        return NO_KEY;
    }
    dwLength = 4;
    DWORD type;
    if(RegQueryValueEx(hKey, "Attribute", 0, &type, (BYTE*)&FileAttribute, &dwLength)
        != ERROR_SUCCESS)
    {
        RegCloseKey(hKey);
        return NO_KEY;
    }
    dwLength = 255;
    if(RegQueryValueEx(hKey, "Time", 0, &type, FileTime, &dwLength)
        != ERROR_SUCCESS)
    {
        RegCloseKey(hKey);
        return NO_KEY;
    }
    FILETIME* temp = (FILETIME*)FileTime;
    FILETIME CreateTime;
    CreateTime = *temp;
    temp ++;
    FILETIME LastAccessTime;
    LastAccessTime = *temp;
    temp ++;
    FILETIME LastWriteTime;
    LastWriteTime = *temp;

    HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if(hFile == INVALID_HANDLE_VALUE)
    {
        MessageBox(NULL, "Please quit TornadoII program!\r\n"
            "Ensure not any program lock TornadoII resource!", "Warnning", MB_OK | MB_ICONHAND);
        return OPEN_ERROR;
    }
//讀資料,判斷該檔案是否可寫
    SetFilePointer(hFile, 0xf0, 0, FILE_BEGIN);
    DWORD dwEntry;
    DWORD dwReaded;
    if(ReadFile(hFile, &dwEntry, 4, &dwReaded, NULL) == FALSE)
    {
        MessageBox(NULL, "Please quit TornadoII program!\r\n"
            "Ensure not any program lock TornadoII resource!", "Warnning", MB_OK | MB_ICONHAND);
        return READ_ERROR;
    }
    if(dwEntry != 0x330)//自己寫的入口
    {
        CloseHandle(hFile);
        return FILE_ERROR;
    }
    DWORD dwWrited;
//1.寫入口
    SetFilePointer(hFile, 0xf0, 0, FILE_BEGIN);
    dwEntry = 0x26df5;
    WriteFile(hFile, &dwEntry, 4, &dwWrited, NULL);

//2.資料
    BYTE buffer[0xc0];
    memset(buffer, 0, sizeof(BYTE) * 0xc0);
    SetFilePointer(hFile, 0x300, 0, FILE_BEGIN);
    WriteFile(hFile, buffer, 0xc0, &dwWrited, NULL);
   
    SetFileTime(hFile, &CreateTime, &LastAccessTime, &LastWriteTime);
    CloseHandle(hFile);
    RegDeleteKey(hKey, "Path");
    RegCloseKey(hKey);
    RegDeleteKey(HKEY_CURRENT_USER, "TNT TornadoII Patch1");
    SetFileAttributes(szFileName, FileAttribute);
   
    return TRUE;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd)
{

    if(WriteBack() == TRUE)
        return TRUE;
    BROWSEINFO  bi;
    ITEMIDLIST* pidl;
    char        path[255];
    memset(path, 0, sizeof(char) * 255);
    bi.hwndOwner = NULL;
    bi.pidlRoot = NULL;
    bi.pszDisplayName = NULL;
    bi.lpszTitle = "Please choose the path of TornadoII installed";
    bi.ulFlags = BIF_BROWSEINCLUDEFILES;
    bi.lpfn = NULL;
    bi.lParam = 0;
    bi.iImage = 0;
    pidl = SHBrowseForFolder(&bi);
    SHGetPathFromIDList(pidl, path);

    char        szFileName[255];
    int        length = strlen(path);

    if(length == 0)
        return FALSE;

    int        temp;
    char*      szName = "\\host\\x86-win32\\bin\\tgtsvr.exe";
    memset(szFileName, 0, sizeof(szFileName));
    memcpy(szFileName, path, length);
    temp = length;
    length = strlen(szName);
    memcpy(&szFileName[temp], szName, length);

    HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if(hFile == INVALID_HANDLE_VALUE)
    {
        MessageBox(NULL, "Please quit TornadoII program!\r\n"
            "Ensure not any program lock TornadoII resource!", "Warnning", MB_OK | MB_ICONHAND);
        return FALSE;
    }

    BY_HANDLE_FILE_INFORMATION FileInfo;
    GetFileInformationByHandle(hFile, &FileInfo);
    CloseHandle(hFile);

    DWORD FileAttribute = FileInfo.dwFileAttributes;
    BYTE FileTime[255];
    memset(FileTime, 0, sizeof(BYTE) * 255);
    length = 0;
    memcpy(&FileTime[length], &FileInfo.ftCreationTime, sizeof(FILETIME));
    length += sizeof(FILETIME);
    memcpy(&FileTime[length], &FileInfo.ftLastAccessTime, sizeof(FILETIME));
    length += sizeof(FILETIME);
    memcpy(&FileTime[length], &FileInfo.ftLastWriteTime, sizeof(FILETIME));
    length += sizeof(FILETIME);
    DWORD newAttribute = FileAttribute & 0xfffffffe;
    SetFileAttributes(szFileName, newAttribute);


    if(WriteCrackData(szFileName) == TRUE)
    {
        HKEY hKey;
        RegCreateKey(HKEY_CURRENT_USER, "TNT TornadoII Patch1", &hKey);
        RegSetValue(hKey, "Path",
            REG_SZ, szFileName, strlen(szFileName));
        RegSetValueEx(hKey, "Attribute", 0, REG_DWORD, (BYTE*)&FileAttribute, 4);
        RegSetValueEx(hKey, "Time", 0, REG_BINARY, FileTime, length);
        if(MessageBox(NULL, "TornadoII Patch1 is OK!\r\nYou can run me again when registered,\r\n"
            "or press yes when you registed.\r\nHave you run TornadoII to register?", "OK!", MB_YESNO) == IDYES)
        {
            WriteBack();
        }
    }

    return TRUE;
}

其中的IDR_CRACKDATA1為:
00000000 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C 00 47 65 74    //KERNEL32.DLL Ge
00000010 56 6F 6C 75 6D 65 49 6E 66 6F 72 6D 61 74 69 6F    //VolumeInformati
00000020 6E 41 00 43 3A 5C 00 00 00 00 00 00 00 00 00 00    //nA C:\
00000030 55 8B EC 83 EC 30 68 00 03 40 00 E8 90 6C 02 00
00000040 68 0D 03 40 00 50 E8 7F 6C 02 00 6A 0A 8D 5D D8
00000050 53 8D 5D D0 53 8D 5D E4 53 8D 5D E8 53 6A 0C 8D
00000060 5D F0 53 68 23 03 40 00 FF D0 8B 45 E8 BB 27 03
00000070 40 00 33 03 BB 33 6F 42 00 89 03 83 C3 04 C6 03
00000080 FF 83 C4 70 8B E5 5D E9 69 6A 02 00 53 BB 33 6F
00000090 42 00 C7 03 FF D0 5B 53 83 C3 04 C6 03 81 8B D8
000000a0 81 C3 0A E1 00 00 C7 03 33 C0 EB 7D 81 EB B7 00
000000b0 00 00 66 C7 03 EB 44 5B E9 76 6B 02 00 00 00 00

後記:
今年7月底破解該軟體,原來想買給xx公司.不過後來失敗了.這也是加GeVolumeInformatinA的原因.
前兩天看到貴論壇上一篇文章,深有感觸.破解應該是一個業餘愛好吧,
希望能和大家交個朋友.

執行該Patch程式注意:
1.保證您已經安裝好TornadoII,且TornadoII的應用程式沒有執行.
2.執行程式patch.
3.選擇TornadoII的安裝路徑.
4.將出現如圖patch1OK.jpg所示,此時patch1已經成功,這時
  patch.exe可以按否關閉,或者不關閉,直接執行TornadoII進行注
  冊.
  注意:現在一定不能馬上按"是"按鈕.如果您按下,那麼只好從第
  二步重新來.
5.註冊TornadoII將出現如register.jpg所示,此時您可以輸入
  任意的26個數字或字母,可以數字和字母混合.註冊成功後,將
  TornadoII的應用程式退出.
6.如果剛才您沒有關閉patch.exe,現在直接按patch1OK.jpg所示的
  "是"按鈕,TornadoII將完全破解.如果您剛才將patch.exe推出了,
  現在需要重新執行他.這一步成功的標誌是patch2OK.jpg所示.
注意:如果您的作業系統是98/95,在第5步時將出現如98.jpg所示(98.jpg不能貼上來,見諒),
    此時實際已經註冊成功.您需要關閉TornadoII的註冊程式,按照
    第六步的指示做.如果您的作業系統是98/95,而且已經過期了,該
     Patch無能為力.只好重灌系統和TII了.:(

相關文章