• 标 题:【献宝】利用DebugAPI做一些原先手工完成的动作,我用这种方法做过内存补丁,内存注册机等,完全VC编译 (6千字)
  • 作 者:bag001
  • 时 间:2002-12-27 11:51:35
  • 链 接:http://bbs.pediy.com

内容:
这段代码针对的是LanTalk XP v2.7.1.0 Build 7123

// LanTalk_ldr.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <stdlib.h>
#include "shlwapi.h"

#pragma comment(lib, "shlwapi.lib")

typedef struct
{
    LPVOID lpAddr;
    BYTE  byData;
    DWORD  nCount;
} BPDATA;

BPDATA g_bpData[10] = {0};
BOOL SetBreakPoint(HANDLE hProcess, LPVOID lpAddr, UINT nNum)
{
    if (nNum >= sizeof(g_bpData) / sizeof(BPDATA)) return FALSE;

    BYTE byTemp;
    DWORD dwNewProt, dwOldProt;

    VirtualProtectEx(hProcess, lpAddr, 1, PAGE_EXECUTE_READWRITE, &dwOldProt);
    BOOL bOK = ReadProcessMemory(hProcess, lpAddr, &byTemp, 1, NULL);
    if (!bOK) goto End;

    g_bpData[nNum].lpAddr = lpAddr;
    g_bpData[nNum].byData = byTemp;
    g_bpData[nNum].nCount = 0;

    byTemp = 0xcc;
    bOK = WriteProcessMemory(hProcess, lpAddr, &byTemp, 1, NULL);
End:
    VirtualProtectEx(hProcess, lpAddr, 1, dwOldProt, &dwNewProt);
    return bOK;
}

BOOL RemoveBreakPoint(HANDLE hProcess, UINT nNum)
{
    if (nNum >= sizeof(g_bpData) / sizeof(BPDATA)) return FALSE;

    BYTE byTemp;
    DWORD dwNewProt, dwOldProt;
    LPVOID lpAddr = g_bpData[nNum].lpAddr;

    VirtualProtectEx(hProcess, lpAddr, 1, PAGE_EXECUTE_READWRITE, &dwOldProt);
    BOOL bOK = ReadProcessMemory(hProcess, lpAddr, &byTemp, 1, NULL);
    bOK = (byTemp == 0xcc);
    if (!bOK) goto End;

    bOK = WriteProcessMemory(hProcess, lpAddr, &g_bpData[nNum].byData, 1, NULL);
    if (bOK) ZeroMemory(g_bpData + nNum, sizeof(BPDATA));
End:
    VirtualProtectEx(hProcess, lpAddr, 1, dwOldProt, &dwNewProt);
    return bOK;
}

BOOL GetDllName(HANDLE hProcess, LPLOAD_DLL_DEBUG_INFO lddi, LPSTR dll_name, int nSize)
{
    LPVOID ptr = 0;
    ReadProcessMemory(hProcess, lddi->lpImageName, &ptr, sizeof(ptr), NULL);
    if( ptr == 0 ) return FALSE;

    WCHAR dll_name_u[MAX_PATH + 1] = {0};
    ReadProcessMemory(hProcess, ptr, dll_name_u, sizeof(dll_name_u), NULL);
    if( dll_name_u[0] == 0 ) return FALSE;

    if( lddi->fUnicode )
        wcstombs(dll_name, dll_name_u, nSize);
    else
        lstrcpyn(dll_name, (LPSTR)dll_name_u, nSize);
    return TRUE;
}


int APIENTRY WinMain(HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR    lpCmdLine,
                    int      nCmdShow)
{
    STARTUPINFO si = {0};
    PROCESS_INFORMATION pi = {0};

    // Start the child process.
    if( !CreateProcess( NULL, // No module name (use command line).
        //"D:\\Program Files\\Lantalk XP\\LanTalk.exe", // Command line.
        "LanTalk.exe",    // Command line.
        NULL,            // Process handle not inheritable.
        NULL,            // Thread handle not inheritable.
        TRUE,            // Set handle inheritance to FALSE.
        DEBUG_ONLY_THIS_PROCESS, // creation flags.
        NULL,            // Use parent's environment block.
        //"D:\\Program Files\\Lantalk XP\\",
        NULL,            // Use parent's starting directory.
        &si,              // Pointer to STARTUPINFO structure.
        &pi )            // Pointer to PROCESS_INFORMATION structure.
    )
    {
        MessageBox(NULL, "CreateProcess failed.", "Error", MB_OK);
        return 0;
    }

    LPVOID lpBase[] = {
        0, // kernel32.GetVersion
        0, // kernel32.GetCommandLineA
        LPBYTE(0x0099f8c0), // get clsid string
        0, // advapi32.RegCreateKeyExA
        LPBYTE(0x00402255), // jnz xxx (75 15) --- change to jmp xxx (eb 15)
    };
    // 设置前两个断点的目的是为了跳过ASProtect 1.2x的解密过程,
    // 第三个断点获得注册表键值
    // 最后一个断点作了一个内存补丁

    HMODULE hModule = LoadLibrary("kernel32.dll");
    lpBase[0] = GetProcAddress(hModule, "GetVersion");
    lpBase[1] = GetProcAddress(hModule, "GetCommandLineA");
    FreeLibrary(hModule);
    hModule = LoadLibrary("advapi32.dll");
    lpBase[3] = GetProcAddress(hModule, "RegCreateKeyExA");
    FreeLibrary(hModule);

    DEBUG_EVENT dbg = {0};
    CONTEXT context = {0};

    while (WaitForDebugEvent(&dbg, INFINITE))
    {
        if (dbg.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT)
        {
            char dll_name[MAX_PATH] = {0};
            if (GetDllName(pi.hProcess, &dbg.u.LoadDll, dll_name, sizeof(dll_name)))
            {
                if (*dll_name)
                {
                    char *p = strrchr(dll_name, '\\');
                    if (p && lstrcmpi(p + 1, "kernel32.dll") == 0)
                        SetBreakPoint(pi.hProcess, lpBase[0], 0);
                }
            }
        }
        else if (dbg.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
        {
            if (dbg.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
            {
                LPVOID lpAddr = dbg.u.Exception.ExceptionRecord.ExceptionAddress;
                if (lpAddr == lpBase[0] || lpAddr == lpBase[1])
                {
                    context.ContextFlags = CONTEXT_CONTROL;
                    if (GetThreadContext(pi.hThread, &context))
                    {
                        RemoveBreakPoint(pi.hProcess, 0);
                        context.Eip--;
                        SetThreadContext(pi.hThread, &context);
                        if (lpAddr == lpBase[0])
                            SetBreakPoint(pi.hProcess, lpBase[1], 0);
                        else
                            SetBreakPoint(pi.hProcess, lpBase[2], 1);
                    }
                }
                else if (lpAddr == lpBase[2])
                {
                    context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
                    if (GetThreadContext(pi.hThread, &context))
                    {
                        RemoveBreakPoint(pi.hProcess, 1);
                        context.Eip--;
                        SetThreadContext(pi.hThread, &context);
                        LPVOID ptr = NULL;
                        if (ReadProcessMemory(pi.hProcess, (LPVOID)context.Ebx, &ptr, sizeof(ptr), NULL))
                        {
                            char szClsid[45] = {0};
                            if (ReadProcessMemory(pi.hProcess, ptr, szClsid, sizeof(szClsid), NULL))
                                SHDeleteKey(HKEY_CLASSES_ROOT, szClsid);
                        }
                        SetBreakPoint(pi.hProcess, lpBase[3], 0);
                    }
                }
                else if (lpAddr == lpBase[3])
                {
                    context.ContextFlags = CONTEXT_CONTROL;
                    if (GetThreadContext(pi.hThread, &context))
                    {
                        RemoveBreakPoint(pi.hProcess, 0);
                        context.Eip--;
                        SetThreadContext(pi.hThread, &context);
                        DWORD dwTemp = 0;
                        ReadProcessMemory(pi.hProcess, lpBase[4], &dwTemp, 4, NULL);
                        if (dwTemp == 0xbe391575)
                        {
                            dwTemp = 0xeb;
                            WriteProcessMemory(pi.hProcess, lpBase[4], &dwTemp, 1, NULL);
                        }
                    }
                }
                ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_CONTINUE);
            }
        }
        else if (dbg.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
            break;
        ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}

  • 标 题:再贴一个使用类似方法的内存注册机, (5千字)
  • 作 者:bag001
  • 时 间:2002-12-27 15:56:57
  • 链 接:http://bbs.pediy.com

一年多以前写的,针对版本有些老(好像是2.4-3.0),新版的算法分析论坛里有,只作方法演示用,代码中使用了特征代码查询方式,以适应版本更新,只要算法不变,可以用在不同版本上。
该软件在计算注册码时分为两部分,前一部分比较简单,后一部分很复杂,但只要使用后一部分算出来的结果根据前一部分的计算逻辑,很容易就可以算出注册码。

// cr-cglc.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

unsigned int decode(unsigned int num);
LPBYTE search(LPBYTE pbuff, int oSize, LPBYTE sub, int subSize)
{
    for (int i = 0; i < oSize - subSize; i++, pbuff++)
    {
        if (*pbuff == *sub)
        {
            if (memcmp(pbuff, sub, subSize) == 0)
                return pbuff;
        }
    }
    return NULL;
}

#define BUFF_SIZE  1024 * 1024
int main(int argc, char* argv[])
{
    STARTUPINFO si = {0};
    PROCESS_INFORMATION pi = {0};

    // Start the child process.
    if( !CreateProcess( NULL, // No module name (use command line).
        "mygp.exe", // Command line.
        NULL,            // Process handle not inheritable.
        NULL,            // Thread handle not inheritable.
        FALSE,            // Set handle inheritance to FALSE.
        0,                // No creation flags.
        NULL,            // Use parent's environment block.
        NULL,            // Use parent's starting directory.
        &si,              // Pointer to STARTUPINFO structure.
        &pi )            // Pointer to PROCESS_INFORMATION structure.
    )
    {
        printf( "CreateProcess failed." );
        return 0;
    }

    WaitForInputIdle(pi.hProcess, INFINITE);

    // 定义特征代码
    unsigned char orig1[] = {0x8b, 0xc6, 0x01, 0x55, 0x88};
    unsigned char orig2[] = {0x29, 0x45, 0x88, 0x8d, 0x45, 0xfc};
    unsigned char orig3[] = {0x29, 0x45, 0x88, 0x83, 0x7d, 0x88, 0x00};
    unsigned char buff1[5], buff2[6], buff3[7];
    
    DWORD bytes;
    LPBYTE lpbase = LPBYTE(0x401000);
    LPBYTE pbuff = new BYTE[BUFF_SIZE];

    // 读取待扫描区域,这里只使用了简单的读定长数据,
    BOOL bok = ReadProcessMemory(pi.hProcess,
        lpbase, pbuff, BUFF_SIZE, &bytes);
    if (!bok)
    {
        delete pbuff;
        return 0;
    }

    // 扫描特征码
    lpbase = search(pbuff, BUFF_SIZE, orig1, sizeof(orig1));
    // 判断找到的位置是否正确
    if (lpbase == NULL ||
        memcmp(lpbase + 10, orig2, sizeof(orig2)) != 0 ||
        memcmp(lpbase + 21, orig3, sizeof(orig3)) != 0)
    {
        delete pbuff;
        printf("regcode not found.");
        TerminateProcess(pi.hProcess, -1);
        CloseHandle( pi.hProcess );
        CloseHandle( pi.hThread );
        return 0;
    }

    lpbase = (LPBYTE)0x401000 + (lpbase - pbuff);
    LPBYTE lpbase1 = lpbase;
    LPBYTE lpbase2 = lpbase + 10;
    LPBYTE lpbase3 = lpbase + 21;
    delete pbuff;

    bok = ReadProcessMemory(pi.hProcess,
        lpbase1, buff1, sizeof(buff1), &bytes);
    if (memcmp(buff1, orig1, sizeof(buff1)) == 0)
    {
        buff1[0] = 0xcc;
        WriteProcessMemory(pi.hProcess,
            lpbase1, buff1, sizeof(buff1), &bytes);
    }

    bok = ReadProcessMemory(pi.hProcess,
        lpbase2, buff2, sizeof(buff2), &bytes);
    // 设置断点1
    if (memcmp(buff2, orig2, sizeof(buff2)) == 0)
    {
        buff2[0] = 0xcc;
        WriteProcessMemory(pi.hProcess,
            lpbase2, buff2, sizeof(buff2), &bytes);
    }

    bok = ReadProcessMemory(pi.hProcess,
        lpbase3, buff3, sizeof(buff3), &bytes);
    // 设置断点2
    if (memcmp(buff3, orig3, sizeof(buff3)) == 0)
    {
        buff3[0] = 0xcc;
        WriteProcessMemory(pi.hProcess,
            lpbase3, buff3, sizeof(buff3), &bytes);
    }

    // 进入调试状态
    bok = DebugActiveProcess(pi.dwProcessId);

    DEBUG_EVENT dbg = {0};
    unsigned int x, y, z;
    CONTEXT context = {0};
    while (WaitForDebugEvent(&dbg, INFINITE))
    {
        if (dbg.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
        {
            if (dbg.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
            {
                if (dbg.u.Exception.ExceptionRecord.ExceptionAddress == lpbase1)
                {
                    context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
                    if (GetThreadContext(pi.hThread, &context))
                    {
                        context.Eip--;
                        WriteProcessMemory(pi.hProcess,
                            lpbase1, orig1, sizeof(orig1), &bytes);
                        SetThreadContext(pi.hThread, &context);
                        bok = ReadProcessMemory(pi.hProcess,
                            LPVOID(context.Ebp - 0x78), &x, sizeof(x), &bytes);
                    }
                }
                else if (dbg.u.Exception.ExceptionRecord.ExceptionAddress == lpbase2)
                {
                    context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
                    if (GetThreadContext(pi.hThread, &context))
                    {
                        context.Eip--;
                        WriteProcessMemory(pi.hProcess,
                            lpbase2, orig2, sizeof(orig2), &bytes);
                        SetThreadContext(pi.hThread, &context);
                        y = context.Eax;
                    }
                }
                else if (dbg.u.Exception.ExceptionRecord.ExceptionAddress == lpbase3)
                {
                    context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
                    if (GetThreadContext(pi.hThread, &context))
                    {
                        context.Eip--;
                        WriteProcessMemory(pi.hProcess,
                            lpbase3, orig3, sizeof(orig3), &bytes);
                        SetThreadContext(pi.hThread, &context);
                        z = context.Eax;

                        printf("Your Register Code is:\n");
                        // 计算注册码
                        printf("%08X\n", decode(y + z - x));
                    }
                }
            }
        }
        else if (dbg.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
            break;
        bok = ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_CONTINUE);
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}

unsigned int decode(unsigned int num)
{
    _asm {
        mov ebx, 3
        mov ecx, num
        xor ecx, 0x81079516
start:
        mov dh, cl
        mov dl, ch
        shl dx, 7
        mov al, dh
        ror eax, 8

        ror ecx, 8
        mov dh, cl
        mov dl, ch
        shl dx, 7
        mov al, dh

        shr ecx, 8
        mov dh, cl
        mov dl, ch
        shl dx, 7
        mov ah, dh

        ror eax, 16

        shr ecx, 8
        mov dh, cl
        mov dl, ch
        shl dx, 7
        mov al, dh

        dec ebx
        jz end
        mov ecx, eax
        jmp start
end:
    }
}

  • 标 题:关于自调试的几点想法 (1千字)
  • 作 者:bag001
  • 时 间:2002-12-27 23:26:12
  • 链 接:http://bbs.pediy.com

据我所知,通常DebugApi只要在两个进程之间就能产生作用,而不管是否在同一个执行档中。

如果你所说的自调试仅仅是指在同一个执行档中进行自我调试的话,Armadillo的加密方法可以说是一个很好的例子。正由于它的自调试方式,使得使用它进行加密的程序天生就具有Anti-Debug能力。

如果是要求在同一个进程中进行自调试,那我们就不能这么做(我从不知道在调用DebugActiveProcess时将当前进程的ID传给它的结果是什么)。

其实调试的过程我们可以看做是程序在某个特定点产生某个事件,由调试器捕捉到该事件进行相应的处理,然后回到断点处继续执行的过程,这一点跟SEH中的EXCEPTION_CONTINUE_EXECUTION方式有些类似,基于这一点考虑,我想是否能够在希望程序产生断点的位置人为的产生某种异常(如div0之类的),让我们事先安装好的异常处理程序来接管控制权进行处理,处理完毕后再返回断点处继续处理。


另外一个想法断点其实就是一个特殊的中断(INT3),我们可以安装一个中断处理程序,在希望断点处发生一个中断,接下来的处理就跟原先的处理差不多了。