劲舞团登录器实现

原理为通过程序A启动游戏主进程,并通过CREATE_SUSPENDED标记挂起,然后向游戏主进程注入dll模块,dll模块中实现游戏进程API调用拦截,逻辑修改等功能。

1、程序A核心代码:

    unsigned int CLaunchShellDlg::SimpleThreadProc(void *arg)
    {
        CLaunchShellDlg *theMainUI = (CLaunchShellDlg *)arg;
        //CString strAppFileName = AfxGetApp()->GetProfileString(_T("STARTUP"), _T("APP"));

        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        memset(&pi, 0, sizeof(PROCESS_INFORMATION));
        memset(&si, 0, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);

        //CString strAppFileName = _T("F:\\游戏专题\\劲舞团Season6.0\\Audition.exe");
        //if (CreateProcess(NULL, strAppFileName.GetBuffer(0), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, _T("F:\\游戏专题\\劲舞团Season6.0"), &si, &pi))
        CString strAppFileName = _T("Audition.exe /T3ENTER qzv5TTNleAJTOzsanttRTQCbExhHDUj");
        if (CreateProcess(NULL, strAppFileName.GetBuffer(0), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
        {
           HANDLE hToken;
           TOKEN_PRIVILEGES tp;
           LUID luid;
            if (!OpenProcessToken(pi.hProcess,TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,&hToken))
            {
                return 0;
            }
            else{
                 if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) return 0;

                  tp.PrivilegeCount = 1;
                  tp.Privileges[0].Luid = luid;
                  tp.Privileges[0].Attributes = 1 ? SE_PRIVILEGE_ENABLED : 0;
                  AdjustTokenPrivileges(hToken,FALSE,&tp,0,0,0);
            }

            // Calculate decode address for inject dll
            char *injectdll = "bf2c6528.dll";
            DWORD hHandle = (DWORD)LoadLibrary(injectdll);
            if (hHandle == 0) goto __ERROR__;
            DWORD hRemoteModule = (DWORD)GetModuleHandle(injectdll);
            if (hRemoteModule == 0) goto __ERROR__;
            DWORD pfndecode = (DWORD)GetProcAddress((HMODULE)hHandle, (LPCSTR)MAKELONG(1, 0));
            //DWORD pfnMapViewOfFileFake = (DWORD)GetProcAddress((HMODULE)hHandle, (LPCSTR)MAKELONG(2, 0));
            FreeLibrary((HMODULE)hHandle);
            if (pfndecode == 0) goto __ERROR__;
            // Calculate offset for decode()
            DWORD offset1 = pfndecode - hRemoteModule;
            //DWORD offset2 = pfnMapViewOfFileFake - hRemoteModule;

            hRemoteModule = InjectDll(pi.hProcess, "bf2c6528");
            pfndecode = hRemoteModule + offset1;
            //pfnMapViewOfFileFake = hRemoteModule + offset2;

            //解决黑屏问题
            unsigned char buf[128];
            SIZE_T out;
            //ReadProcessMemory(pi.hProcess, (LPCVOID)0x0044B00E, buf, sizeof(buf), &out);
            memset(buf, 0x90, sizeof(buf));
            WriteProcessMemory(pi.hProcess, (LPVOID)0x0044AFFE, buf, 5, &out);
            WriteProcessMemory(pi.hProcess, (LPVOID)0x0044B00E, buf, 1, &out);
            WriteProcessMemory(pi.hProcess, (LPVOID)0x0044B046, buf, 6, &out);
    #if 0
            // JMP to MapViewOfFileFake
            //buf[0] = 0xe8; buf[5] = 0x90;
            //DWORD jmpAddr = pfnMapViewOfFileFake - 0x00439D55 - 5;
            //memcpy(&buf[1], &jmpAddr, 4);
            //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D55, buf, 6, &out);

            // Test Code; JMP to fixed address
            //buf[0] = 0xe8; buf[1] = 0x3b; buf[2] = 0x1c; buf[3] = 0x3d;
            //buf[4] = 0x7c; buf[5] = 0x90;
            //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D55, buf, 6, &out);

            //buf[0] = 0x00;
            //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439CFC, buf, 1, &out);
            //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439CA6, buf, 1, &out);
    #endif

    #if 1
            //buf[0] = 0x10;
            //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D21, buf, 1, &out);
            //buf[0] = 0x04;
            //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D40, buf, 1, &out);
            //buf[0] = 0x04;
            //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D4D, buf, 1, &out);

            void *pAddrRemote = ::VirtualAllocEx( pi.hProcess, NULL, 0x100,
                                   MEM_COMMIT, PAGE_READWRITE );

            DWORD jmpAddr = 0x00439D55;
            int codeSize = 6;
            ReadProcessMemory(pi.hProcess, (LPCVOID)jmpAddr, buf, codeSize, &out);
            WriteProcessMemory(pi.hProcess, (LPVOID)pAddrRemote, buf, codeSize, &out);

            // JMP [DST], 5 bytes
            DWORD address = (DWORD)pAddrRemote - jmpAddr - 5;
            memcpy(&buf[1], &address, 4);
            buf[0] = 0xE9; buf[5] = 0x90;
            WriteProcessMemory(pi.hProcess, (LPVOID)jmpAddr, buf, codeSize, &out);

            // Calculate JMP/CALL address and replace \xff\xff\xff\xff
            char shellcode[] =
                "\xff\xb6\x1c\x59\x87\x00\x6a\x00\x50\x8d\x84\x24\xa4\x01\x00\x00\x50\xe8\xff\xff"
                 "\xff\xff\xe9\xff\xff\xff\xff";
            int len = sizeof(shellcode) - 1;
            pAddrRemote = (char *)pAddrRemote + 6;
            jmpAddr = pfndecode - ((DWORD)pAddrRemote + len - 10) - 5;
            memcpy(&shellcode[len - 9], &jmpAddr, 4);

            jmpAddr = 0x00439D5B - ((DWORD)pAddrRemote + len - 5) - 5;
            memcpy(&shellcode[len - 4], &jmpAddr, 4);
            BOOL bRet = WriteProcessMemory(pi.hProcess, (LPVOID)pAddrRemote, shellcode, len, &out);
    #endif

    #if 0
            // Test Code : JMP to original
            buf[0] = 0xE9; buf[5] = 0x90;
            pAddrRemote = (char *)pAddrRemote + 6;
            address = jmpAddr + codeSize - (DWORD)pAddrRemote - 5;
            memcpy(&buf[1], &address, 4);
            WriteProcessMemory(pi.hProcess, (LPVOID)pAddrRemote, buf, 6, &out);
    #endif

            int ret = ::ResumeThread(pi.hThread);
            //Sleep(1000);//If this is not here, everything goes to hell
            //WaitForSingleObject(pi.hProcess,INFINITE);
            //CloseHandle(pi.hProcess);
            //CloseHandle(pi.hThread);
            //theMainUI->shutdownWindows();
        }
        else
        {
            goto __ERROR__;
        }
        return 0;

    __ERROR__:
        ::MessageBox(0, "登录器出现错误", "提示", MB_OK);
        return -1;
    }

类似下面代码中出现的进程绝对地址是通过Olldbg分析工具得到的,直接修改对应的代码。

WriteProcessMemory(pi.hProcess, (LPVOID)0x0044AFFE, buf, 5, &out);
WriteProcessMemory(pi.hProcess, (LPVOID)0x0044B00E, buf, 1, &out);
WriteProcessMemory(pi.hProcess, (LPVOID)0x0044B046, buf, 6, &amp;out);</pre>

2、注入dll代码

模块功能对acv地图数据进行解密,测试了一个文件。模块也测试过用MapViewOfFileFake拦截 MapViewOfFile,只要替换对应的函数跳转地址即可。

    char * __stdcall decode(char *fileName, char *lpMapAddress, int size, HANDLE hFile)
    {
        if (hFile != NULL)
        {
            size = GetFileSize(hFile, 0);
        }

        if (stricmp(fileName, "data/009.acv") == 0)
        {
            //char str[128];
            //memset(str, 0, sizeof(str));
            //_itoa(size, str, 10);

            ////MessageBox(0, fileName, "File Name...", MB_OK);
            //MessageBox(0, str, "", MB_OK);

            //char *pMem = (char *)malloc(bufsize);
            //memcpy(pMem, buf, bufsize);
            //buf = pMem;

            HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, 
                NULL, PAGE_READWRITE, 0, size, NULL);
            char *buf = (char *)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
            memcpy(buf, lpMapAddress, size);

            for (int i = 0; i < size; i++)
            {
                buf[i] = buf[i] ^ 0x68;
            }

            UnmapViewOfFile( (LPCVOID)lpMapAddress );
            lpMapAddress = buf;
        }

        return lpMapAddress;
    }

    #include <stdio.h>
    #include <string.h>
    #include <malloc.h>
    #include <crtdbg.h>

    char *gMappingAddress = NULL;

    LPVOID WINAPI MapViewOfFileFake(
               HANDLE hFileMappingObject,
               DWORD dwDesiredAccess,
               DWORD dwFileOffsetHigh,
               DWORD dwFileOffsetLow,
               SIZE_T dwNumberOfBytesToMap
    )
    {
        char *buf = (char *)MapViewOfFile(
                                hFileMappingObject,
                                0x06,
                                dwFileOffsetHigh,
                                dwFileOffsetLow,
                                dwNumberOfBytesToMap);

        //MEMORY_BASIC_INFORMATION mem_info;
        //int size = (int)VirtualQuery((void*)buf, &amp;mem_info, sizeof(mem_info));

        //char str[128];
        //memset(str, 0, sizeof(str));
        //_itoa(size, str, 10);
        //MessageBox(0, str, "", MB_OK);

        //char *pMem = (char *)malloc(size);
        //memcpy(pMem, buf, size);

        return buf;
    }

    BOOL WINAPI UnmapViewOfFileFake(
            LPCVOID lpBaseAddress
    )
    {

        return UnmapViewOfFile(lpBaseAddress);
    }

注入模块dll 导出函数定义,要隐藏函数,防止被猜解:

EXPORTS
    1=decode @1
    2=MapViewOfFileFake  @2
    3=UnmapViewOfFileFake @3</pre>

留言