searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

某某市信息科技学业水平测试软件打开加载失败逆向分析

2024-07-17 09:39:41
9
0

引言:笔者在工作过程中遇到,用户上报某某市信息科技学业水平测试软件在云电脑上打开初始化的情况下出现了加载和绑定机器失败的问题。一般情况下,在实体机上用户进行登录后,用户的账号信息跟主机的机器码进行绑定然后保存到配置文件,等下次再次登录的时候就可以不用再次输入用户账户信息的情况下完成自动登录。但是用户反馈在我们的云电脑上出现了无法完成自动登录的情况。


解决过程:

用dbgx64.exe对该软件进行逆向调试分析(这里过程复杂,不具体罗列),发现该软件是用vb写的程序,并最后调试并发现该软件获取机器序列号的函数,该软件是通过DeviceIoControl这个Api来获取机器的序列号的,通过hook该Api发现该软件会调用三次DeviceIoControl这个api来获取机器码。到底要hook哪一次的调用呢。

通过在网上找到vb程序写的获取机器码的相关代码。通过vb6.0对改代码进行调试,发现该代码基本就是该软件获取机器码的方式:

并发现,在云桌面上每次通过DeviceIoCtrol获取的机器码都是不一样的,而在实体机上发现,该Api调用会返回失败,但为什么在实体机软件能运行正常呢,这里猜测是软件在获取机器码失败的情况会通过固定算法自动生成一个ID的方式来替代本机的机器码,而在云主机上由于每次调用DeviceIoCtrol都能调用成功,但是获取的机器码不一样导致校验失败。

这里通过Hook DeviceIoCtrol并根据特定的ID进行返回失败操作来达到目的。可以通过CFF对软件进行修改导入表的方式来完成软件对自己插件的自动依赖和加载,但同时考虑到软件软件的升级,所以这里不建议直接给软件程序打补丁,而是通过对软件依赖的msvbvm60.dll进行打补丁(打补丁可以通过CFF Explorer_EN修改msvbvm60.dll的导入表,让msvbvm60.dll依赖自己的dll的方式来第一时间注入 ),这样哪怕软件完成了升级也不会导致因为软件文件升级而导致补丁加载失效:


附录代码:
static BOOL(WINAPI* OrgDeviceIoControl)(
    HANDLE       hDevice,
    DWORD        dwIoControlCode,
    LPVOID       lpInBuffer,
    DWORD        nInBufferSize,
    LPVOID       lpOutBuffer,
    DWORD        nOutBufferSize,
    LPDWORD      lpBytesReturned,
    LPOVERLAPPED lpOverlapped
) = DeviceIoControl;
 
BOOL WINAPI NewDeviceIoControl(
    HANDLE       hDevice,
    DWORD        dwIoControlCode,
    LPVOID       lpInBuffer,
    DWORD        nInBufferSize,
    LPVOID       lpOutBuffer,
    DWORD        nOutBufferSize,
    LPDWORD      lpBytesReturned,
    LPOVERLAPPED lpOverlapped
)
{
     BOOL bRet = OrgDeviceIoControl(hDevice,
        dwIoControlCode,
        lpInBuffer,
        nInBufferSize,
        lpOutBuffer,
        nOutBufferSize,
        lpBytesReturned,
        lpOverlapped);
 
     //IOCTL_DISK_GET_DRIVE_GEOMETRY;
 
    /* if (0x74080 == dwIoControlCode || 0x7C084 == dwIoControlCode || dwIoControlCode == 0x7C088)
     {
         bRet = FALSE;
         return FALSE;
     } */
 
     if (dwIoControlCode == 0x7C088)
     {
         bRet = FALSE;
         OutputDebugString(L"DeviceIoCtrol Code is 0x7C088, process it!");
 
         SENDCMDOUTPARAMS out;
         int outparamsize = sizeof(out);
         memcpy(&out, lpOutBuffer, sizeof(out));
 
         IDSECTOR idsector;
         memcpy(&idsector, &out.bBuffer[0], sizeof(idsector));
 
         char* pcNumber = idsector.sModelNumber;
         __int64 pNumber = (__int64)pcNumber;
         __int64 pFirmware = (__int64)idsector.sFirmwareRev;
         __int64 pSerNum = (__int64)idsector.sSerialNumber;
 
         WCHAR szBuf[350] = { 0 };
         wsprintf(szBuf, L" sModelNumber 1:0x%p  0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n",
             pcNumber, *(char*)(pNumber+0), *(char*)(pNumber + 1), *(char*)(pNumber + 2), *(char*)(pNumber + 3), *(char*)(pNumber + 4), *(char*)(pNumber + 5), *(char*)(pNumber + 6), *(char*)(pNumber + 7),
             *(char*)(pNumber + 8), *(char*)(pNumber + 9), *(char*)(pNumber + 10), *(char*)(pNumber + 11), *(char*)(pNumber + 12), *(char*)(pNumber + 13), *(char*)(pNumber + 14), *(char*)(pNumber + 15),
             *(char*)(pNumber + 16), *(char*)(pNumber + 17), *(char*)(pNumber + 18), *(char*)(pNumber + 19), *(char*)(pNumber + 20), *(char*)(pNumber + 21), *(char*)(pNumber + 22), *(char*)(pNumber + 23),
             *(char*)(pNumber + 24), *(char*)(pNumber + 25), *(char*)(pNumber + 26), *(char*)(pNumber + 27), *(char*)(pNumber + 28), *(char*)(pNumber + 29), *(char*)(pNumber + 30), *(char*)(pNumber + 31),
             *(char*)(pNumber + 32), *(char*)(pNumber + 33), *(char*)(pNumber + 34), *(char*)(pNumber + 35), *(char*)(pNumber + 36), *(char*)(pNumber + 37), *(char*)(pNumber + 38), *(char*)(pNumber + 39)
            );
         OutputDebugStringW(szBuf);
 
         wsprintf(szBuf, L" sFirmwareRev 2:0x%p  0x%02X %02X %02X %02X %02X %02X %02X %02X \n",
              pFirmware, *(char*)(pFirmware + 0), *(char*)(pFirmware + 1), *(char*)(pFirmware + 2), *(char*)(pFirmware + 3), *(char*)(pFirmware + 4), *(char*)(pFirmware + 5), *(char*)(pFirmware + 6), *(char*)(pFirmware + 7));
         OutputDebugStringW(szBuf);
 
         wsprintf(szBuf, 
             L"sSerialNumber 3:0x%p  0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X \n",
             pSerNum, *(char*)(pSerNum + 0), *(char*)(pSerNum + 1), *(char*)(pSerNum + 2), *(char*)(pSerNum + 3), *(char*)(pSerNum + 4), *(char*)(pSerNum + 5), *(char*)(pSerNum + 6), *(char*)(pSerNum + 7),
             *(char*)(pSerNum + 8), *(char*)(pSerNum + 9), *(char*)(pSerNum + 10), *(char*)(pSerNum + 11), *(char*)(pSerNum + 12), *(char*)(pSerNum + 13), *(char*)(pSerNum + 14), *(char*)(pSerNum + 15),
             *(char*)(pSerNum + 16), *(char*)(pSerNum + 17), *(char*)(pSerNum + 18), *(char*)(pSerNum + 19)
         );
         OutputDebugStringW(szBuf);
     }
     return bRet;
}
 
bool Hook()
{
    // 相关的初始化信息
    DetourTransactionBegin();
    // 更新线程信息 
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)OrgDeviceIoControl, NewDeviceIoControl);
 
//    org_vbaStrCmp = (_vbaStrCmp)GetProcAddress(LoadLibraryA("msvbvm60.dll"), "__vbaStrCmp");
    //int iRet2 = DetourAttach(&(PVOID&)org_vbaStrCmp, new_vbaStrCmp);
 
    return NO_ERROR == DetourTransactionCommit();
}
 
// 卸载Hook
bool UnHoo()
{
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    return NO_ERROR == DetourTransactionCommit();
}

0条评论
0 / 1000
廖****龙
11文章数
2粉丝数
廖****龙
11 文章 | 2 粉丝
原创

某某市信息科技学业水平测试软件打开加载失败逆向分析

2024-07-17 09:39:41
9
0

引言:笔者在工作过程中遇到,用户上报某某市信息科技学业水平测试软件在云电脑上打开初始化的情况下出现了加载和绑定机器失败的问题。一般情况下,在实体机上用户进行登录后,用户的账号信息跟主机的机器码进行绑定然后保存到配置文件,等下次再次登录的时候就可以不用再次输入用户账户信息的情况下完成自动登录。但是用户反馈在我们的云电脑上出现了无法完成自动登录的情况。


解决过程:

用dbgx64.exe对该软件进行逆向调试分析(这里过程复杂,不具体罗列),发现该软件是用vb写的程序,并最后调试并发现该软件获取机器序列号的函数,该软件是通过DeviceIoControl这个Api来获取机器的序列号的,通过hook该Api发现该软件会调用三次DeviceIoControl这个api来获取机器码。到底要hook哪一次的调用呢。

通过在网上找到vb程序写的获取机器码的相关代码。通过vb6.0对改代码进行调试,发现该代码基本就是该软件获取机器码的方式:

并发现,在云桌面上每次通过DeviceIoCtrol获取的机器码都是不一样的,而在实体机上发现,该Api调用会返回失败,但为什么在实体机软件能运行正常呢,这里猜测是软件在获取机器码失败的情况会通过固定算法自动生成一个ID的方式来替代本机的机器码,而在云主机上由于每次调用DeviceIoCtrol都能调用成功,但是获取的机器码不一样导致校验失败。

这里通过Hook DeviceIoCtrol并根据特定的ID进行返回失败操作来达到目的。可以通过CFF对软件进行修改导入表的方式来完成软件对自己插件的自动依赖和加载,但同时考虑到软件软件的升级,所以这里不建议直接给软件程序打补丁,而是通过对软件依赖的msvbvm60.dll进行打补丁(打补丁可以通过CFF Explorer_EN修改msvbvm60.dll的导入表,让msvbvm60.dll依赖自己的dll的方式来第一时间注入 ),这样哪怕软件完成了升级也不会导致因为软件文件升级而导致补丁加载失效:


附录代码:
static BOOL(WINAPI* OrgDeviceIoControl)(
    HANDLE       hDevice,
    DWORD        dwIoControlCode,
    LPVOID       lpInBuffer,
    DWORD        nInBufferSize,
    LPVOID       lpOutBuffer,
    DWORD        nOutBufferSize,
    LPDWORD      lpBytesReturned,
    LPOVERLAPPED lpOverlapped
) = DeviceIoControl;
 
BOOL WINAPI NewDeviceIoControl(
    HANDLE       hDevice,
    DWORD        dwIoControlCode,
    LPVOID       lpInBuffer,
    DWORD        nInBufferSize,
    LPVOID       lpOutBuffer,
    DWORD        nOutBufferSize,
    LPDWORD      lpBytesReturned,
    LPOVERLAPPED lpOverlapped
)
{
     BOOL bRet = OrgDeviceIoControl(hDevice,
        dwIoControlCode,
        lpInBuffer,
        nInBufferSize,
        lpOutBuffer,
        nOutBufferSize,
        lpBytesReturned,
        lpOverlapped);
 
     //IOCTL_DISK_GET_DRIVE_GEOMETRY;
 
    /* if (0x74080 == dwIoControlCode || 0x7C084 == dwIoControlCode || dwIoControlCode == 0x7C088)
     {
         bRet = FALSE;
         return FALSE;
     } */
 
     if (dwIoControlCode == 0x7C088)
     {
         bRet = FALSE;
         OutputDebugString(L"DeviceIoCtrol Code is 0x7C088, process it!");
 
         SENDCMDOUTPARAMS out;
         int outparamsize = sizeof(out);
         memcpy(&out, lpOutBuffer, sizeof(out));
 
         IDSECTOR idsector;
         memcpy(&idsector, &out.bBuffer[0], sizeof(idsector));
 
         char* pcNumber = idsector.sModelNumber;
         __int64 pNumber = (__int64)pcNumber;
         __int64 pFirmware = (__int64)idsector.sFirmwareRev;
         __int64 pSerNum = (__int64)idsector.sSerialNumber;
 
         WCHAR szBuf[350] = { 0 };
         wsprintf(szBuf, L" sModelNumber 1:0x%p  0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n",
             pcNumber, *(char*)(pNumber+0), *(char*)(pNumber + 1), *(char*)(pNumber + 2), *(char*)(pNumber + 3), *(char*)(pNumber + 4), *(char*)(pNumber + 5), *(char*)(pNumber + 6), *(char*)(pNumber + 7),
             *(char*)(pNumber + 8), *(char*)(pNumber + 9), *(char*)(pNumber + 10), *(char*)(pNumber + 11), *(char*)(pNumber + 12), *(char*)(pNumber + 13), *(char*)(pNumber + 14), *(char*)(pNumber + 15),
             *(char*)(pNumber + 16), *(char*)(pNumber + 17), *(char*)(pNumber + 18), *(char*)(pNumber + 19), *(char*)(pNumber + 20), *(char*)(pNumber + 21), *(char*)(pNumber + 22), *(char*)(pNumber + 23),
             *(char*)(pNumber + 24), *(char*)(pNumber + 25), *(char*)(pNumber + 26), *(char*)(pNumber + 27), *(char*)(pNumber + 28), *(char*)(pNumber + 29), *(char*)(pNumber + 30), *(char*)(pNumber + 31),
             *(char*)(pNumber + 32), *(char*)(pNumber + 33), *(char*)(pNumber + 34), *(char*)(pNumber + 35), *(char*)(pNumber + 36), *(char*)(pNumber + 37), *(char*)(pNumber + 38), *(char*)(pNumber + 39)
            );
         OutputDebugStringW(szBuf);
 
         wsprintf(szBuf, L" sFirmwareRev 2:0x%p  0x%02X %02X %02X %02X %02X %02X %02X %02X \n",
              pFirmware, *(char*)(pFirmware + 0), *(char*)(pFirmware + 1), *(char*)(pFirmware + 2), *(char*)(pFirmware + 3), *(char*)(pFirmware + 4), *(char*)(pFirmware + 5), *(char*)(pFirmware + 6), *(char*)(pFirmware + 7));
         OutputDebugStringW(szBuf);
 
         wsprintf(szBuf, 
             L"sSerialNumber 3:0x%p  0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"
             L"0x%02X %02X %02X %02X \n",
             pSerNum, *(char*)(pSerNum + 0), *(char*)(pSerNum + 1), *(char*)(pSerNum + 2), *(char*)(pSerNum + 3), *(char*)(pSerNum + 4), *(char*)(pSerNum + 5), *(char*)(pSerNum + 6), *(char*)(pSerNum + 7),
             *(char*)(pSerNum + 8), *(char*)(pSerNum + 9), *(char*)(pSerNum + 10), *(char*)(pSerNum + 11), *(char*)(pSerNum + 12), *(char*)(pSerNum + 13), *(char*)(pSerNum + 14), *(char*)(pSerNum + 15),
             *(char*)(pSerNum + 16), *(char*)(pSerNum + 17), *(char*)(pSerNum + 18), *(char*)(pSerNum + 19)
         );
         OutputDebugStringW(szBuf);
     }
     return bRet;
}
 
bool Hook()
{
    // 相关的初始化信息
    DetourTransactionBegin();
    // 更新线程信息 
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)OrgDeviceIoControl, NewDeviceIoControl);
 
//    org_vbaStrCmp = (_vbaStrCmp)GetProcAddress(LoadLibraryA("msvbvm60.dll"), "__vbaStrCmp");
    //int iRet2 = DetourAttach(&(PVOID&)org_vbaStrCmp, new_vbaStrCmp);
 
    return NO_ERROR == DetourTransactionCommit();
}
 
// 卸载Hook
bool UnHoo()
{
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    return NO_ERROR == DetourTransactionCommit();
}

文章来自个人专栏
个人原创文章
11 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0