吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 13310|回复: 83
收起左侧

[原创] vmp 3.8.1反调试分析与手动绕过

  [复制链接]
寞叶 发表于 2023-8-25 02:46
环境:
vmp版本:3.8.1 professional  为了方便分析,只勾选反调试选项(user-mode+kernel-mode)
待分析样本: x32 编译环境vs2022
系统环境:windows 11 cpu:amd
用到的调试器 OllyDbg, windbg
本人水平有限,如果哪里有不对请指出 :)



初始化工作:
首先vmp会调用RtlAllocateHeap
然后通过peb取到ldr链来获取ntdll的模块基址(图中高亮行),接着使用二分查找通过解析导出表获取ZwQueryInformationProcess的地址,然后调用他


image-1.png

vmp会判断0xcc断点,不要在函数头下断,可以用硬件断点
image-2.png

参数0x1a(ProcessWow64Information)表示查询进程是否运行在wow64下(影响后续反调试流程,本文仅分析当前流程下vmp走的反调试流程)
接着通过遍历ntdll的资源信息来判断电脑系统版本

image-3.png

然后调用ZwOpenSectionZwMapViewOfSection copy 一份 ntdll,通过特征码0xb8获取函数的服务号
完成之后接着调用ZwUnmapViewOfSectionZwClose
在OD中观察程序刚加载时的esp的上方可以发现一些数据(标红即被修改的)

image-4.png

左边不难猜测是vmp用来进行直接系统调用的服务号,0xD  ZwSetInformationThread印象深刻...右边则有一些有趣的函数的地址
分析到这忽然想起前段时间vmp源码(据说是3.5版本?)泄露了部分,我对照着看了一下,目前的流程不能说是相似,简直一模一样

        
image-5.png


开始进行反调试:
紧接着,根据以下条件进行不同的反调试。
1、是否是wow64环境(前面有提到)
2、系统的版本(fs:[0x30]+0x0a4 OSMajorVersion   : Uint4B)下图高亮行
3、处理器类型(KUSER_SHARED_DATA + 0x26a NativeProcessorArchitecture : Uint2B)下图高亮行的下一行

image-6.png
        
如图,在当前环境下,vmp用“天堂之门”将代码切换到x64执行。然后我就干瞪眼了半天,OD没法调试x64的代码
与此同时我注意到切换到x64之后的代码似乎仍然是在虚拟机里执行的,所以我选择先对程序进行了一些黑盒测试
在我的系统是win11,程序运行在wow64的前提下,似乎只有NativeProcessorArchitecture为amd时vmp才会用“天堂之门”将代码切换至x64继续执行。尝试修改读取到的NativeProcessorArchitecture, 其余都是直接走x32的,我也不是很清楚具体原因
除此之外我在jmp far 和返回地址00C7CE2A处分别下硬件执行断点,然后F9运行几次,发现经过两次x32到x64切换之后,vmp似乎已经检测出调试器,使用NtRaiseHardError来弹窗提示然后退出。然后我通过观察堆栈,发现有一处红色变动的值0xFFFFFFFF,我尝试将其置0,发现流程继续下去到了第三个jmp far,之后再弹窗退出。此时很明显已经干预了一处反调试的结果。

        
image-7.png

因为od、x32dbg、x64dbg都没办法在切换成x64后调试,所以我就用unicorn模拟执行和windbg来继续分析x64代码(吐槽一下,切换x64之后还是在虚拟机里执行代码,好恶心啊)
可以发现在切换到x64代码后,vmp进行直接系统调用(rax=0x1c ZwSetInformationProcess)来disable InstrumentationCallback
参数 ProcessInformationClass = 0x28

        
image-8.png
        
然后我尝试对syscall下断,发现程序直接异常退出或者断不下来
这是有两个原因,第一个原因是vmp检测了0xCC断点
另一个原因是:vmp通过指令rdtsc的返回值,从多个不同但结果相同的路径中随机选择一个路径执行,尝试修改rdtsc返回值,会发现模拟到不同的路径。这也就是为什么实际执行和模拟的结果不同(可以通过patch rdtsc返回值让他实际走的流程跟模拟流程一致)
既然在切换到x64之后仍然是进行直接系统调用,并且他没有访问一些其他内存(或者做其他一些操作),而且我发现他前2次x32切换到x64都是走这个jmp far,我就有了个大胆的想法。它应该是有个类似的封装好的函数可以走x64系统调用,想象中的几句伪代码如下

[Asm] 纯文本查看 复制代码
x64_code:

​        (可能是一些准备工作)

​        syscall

​        (将结果保存等等)

​        retf



function MakeX64DirectSystemCall (服务号,参数1,参数2,...,返回值):

​                

​                push cs

​                push ret_addr

​                jmp far 0x33: x64_code

​                ret_addr:

​                nop

​                mov cx,ss

​                mov ss,cx

​                (不太清楚后续代码)

end



push &返回值

push 参数

push 服务号

call MakeX64DirectSystemCall



于是我尝试了几次,最后发现在数据窗口中跟随ebp,修改这里附近的值,模拟时发现调用号被修改成功,再试试参数是否能修改,发现也可以。这下可以操作的空间就很多啦。
只不过我还有一个疑惑,就是为什么x64返回到x32的时候,头3条汇编指令是

[Asm] 纯文本查看 复制代码
nop
mov cx,ss
mov ss,cx


虽然我知道有类似的方法可以反单步跟踪和反虚拟机,但是第四条指令是pushfd,这里第四条指令不是
现在我们不跟x64代码也知道他要做什么操作了
然后vmp通过直接系统调用(0x19 ZwQueryInformationProcess) 参数ProcessInformationClass= ProcessDebugPort= 0x7
查询调试端口号(在返回地址将结果0x0019fed8处将FFFFFFFF置0即可绕过)

(补充:注意下图标红的地方,从左到右依次是服务号,参数,末尾存放返回值)

image-9.png


然后到另一处jmp far 通过直接系统调用(0x19 ZwQueryInformationProcess) 参数ProcessInformationClass= ProcessDebugObjectHandle = 0x1E
查询调试对象句柄
但是这次结果是存放在另一个地方(r8=0x0019f72c)

image-10.png

将0x0019f72c处查询到的句柄置0,并且返回值(存放在堆栈上)置0xC0000353(STATUS_PORT_NOT_SET)即可绕过。(实际测试的时候改句柄发现没用,仅需返回值<0,甚至句柄有值都能过,感觉逻辑可能得改改?)
image-11.png

然后调用ZwSetInformationThread,参数0x11 ThreadHideFromDebugger,绕过方法:将0x11置0即可

image-12.png

--接下来是kernel-mode反调试--
在上面调用完ZwSetInformationThread之后,调用ZwQuerySystemInformation(SystemInformationClass==0x23)查询系统是否在调试模式下运行。
直接将存放结果的缓冲区置0即可

image-13.png

        
然后再调用两次该函数,查询内核模块信息(SystemInformationClass==SystemModuleInformation==0xB)
第一次是获取需要的缓冲区长度,第二次是获取真正的信息。直接在第一次将返回的长度置0即可
在此之后,vmp会对pe头、资源等数据进行读取校验。

image-14.png

在这之后再一次调用ZwQueryInformationProcess查询调试端口和ZwSetInformationThread进行反调试。绕过方法跟前面操作相似
然后反调试就成功绕过,程序就跑起来啦:)

image-15.png



小小的总结一下:

注意对api下断时不要在函数头下断,容易被检测
vmp反调试全程跑在虚拟机内,可以通过分析他的api调用以及访问的内存来推测相关逻辑
突发奇想的伪代码对x32->x64调用逻辑的帮助简化了分析流程,不必每次都模拟切换x64代码,让我顺利完成了此次分析
如果要自动绕过反调试的话,估计要写个驱动?或者如果要手动分析的话直接根据特征码对vmp段所有“天堂之门”全部下断,x64切换和返回的汇编特征还是很明显的(注意别对push cs或者返回时的nop下断,会检测0xcc)




(忘了附代码了,补上模拟x64的代码)
[C++] 纯文本查看 复制代码
#include <cassert>
#include <windows.h>
#include <cstdio>
#include <iostream>
#include <TlHelp32.h>
#include <vector>
#include "unicorn-2.0.1-win32/include/unicorn/unicorn.h"
#include "capstone-5.0/include/capstone/capstone.h"
using namespace std;
uc_engine* uc;
uc_err uc_error;
csh cshandle;
cs_insn* insn;
cs_err cs_error;
size_t count;
BYTE Buffer[5000000];
//jmp far 1
// UINT64 rax = 0x0000000000000004;
// UINT64 rbx = 0x00000000ff5d11cf;
// UINT64 rcx = 0x000000000019f6bc;
// UINT64 rdx = 0x0000000000c7bf47;
// UINT64 rsi = 0x0000000000bb8baa;
// UINT64 rdi = 0x0000000000bbe808;
// UINT64 rsp = 0x000000000019f630;
// UINT64 rbp = 0x000000000019f748;
// UINT64 r8 = 0x000000000000002b;
// UINT64 r9 = 0x000000007757624c;
// UINT64 r10 = 0x0000000000000000;
// UINT64 r11 = 0x0000000000000246;
// UINT64 r12 = 0x000000000024f000;
// UINT64 r13 = 0x000000000009fda0;
// UINT64 r14 = 0x000000000009ed00;
// UINT64 r15 = 0x00000000774f4770;
// UINT64 rip = 0x0000000000c5c9e8;
// UINT64 rfl = 0x0000000000000206;

//jmp far 3
// uint64_t rax = 0x0000000000000032   ;
// uint64_t rbx = 0x000000000087c678   ;
// uint64_t rcx = 0x0000000000000005   ;
// uint64_t rdx = 0x000000000019f6bc   ;
// uint64_t rsi = 0x000000000019f744   ;
// uint64_t rdi = 0x0000000000c3cd0d   ;
// uint64_t rip = 0x0000000000a9040b   ;
// uint64_t rsp = 0x000000000019f630   ;
// uint64_t rbp = 0x0000000000acc57b   ;
// uint64_t r8 =  0x000000000019f5e8   ;
// uint64_t r9 =  0x0000000000000000   ;
// uint64_t r10 = 0x00000000ffffffff   ;
// uint64_t r11 = 0x0000000000000246   ;
// uint64_t r12 = 0x000000000021d000   ;
// uint64_t r13 = 0x000000000009fda0   ;
// uint64_t r14 = 0x000000000009ed00   ;
// uint64_t r15 = 0x00000000774f4770   ;
// uint64_t rfl = 0x0000000000000206   ;

//jmp far 4
uint64_t rax = 0x0019F6BC;
uint64_t rbx = 0x00811B46;
uint64_t rcx = 0x00000005;
uint64_t rdx = 0x001401A8;
uint64_t rsi = 0x0019F744;
uint64_t rdi = 0x00A022B8;
uint64_t rip = 0x00c6dab8;
uint64_t rsp = 0x0019F630;
uint64_t rbp = 0x00A2E676;
uint64_t r8 =  0x000000000019f5e8   ;
uint64_t r9 =  0x0000000000000000   ;
uint64_t r10 = 0x00000000ffffffff   ;
uint64_t r11 = 0x0000000000000246   ;
uint64_t r12 = 0x000000000021d000   ;
uint64_t r13 = 0x000000000009fda0   ;
uint64_t r14 = 0x000000000009ed00   ;
uint64_t r15 = 0x00000000774f4770   ;
uint64_t rfl = 0x0000000000000206   ;


HANDLE FindProcessByName(const char* name)
{
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    {
        return NULL;
    }
    if (Process32First(hProcessSnap, &pe32))
    {
        do
        {
            if (strcmp(pe32.szExeFile, name) == 0)
            {
                CloseHandle(hProcessSnap);
                return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
            }
        } while (Process32Next(hProcessSnap, &pe32));
    }
    CloseHandle(hProcessSnap);
    return NULL;
}

/**
 * [url=home.php?mod=space&uid=190858]@brief[/url] 枚举指定进程所有内存块
 * [url=home.php?mod=space&uid=952169]@Param[/url] hProcess [in] 要枚举的进程,至少需拥有PROCESS_QUERY_INFORMATION权限
 * @param memories [out] 返回枚举到的内存块数组
 * [url=home.php?mod=space&uid=155549]@Return[/url] 成功返回true,失败返回false.
 */
int my_EnumAllMemoryBlocks(HANDLE hProcess, vector <MEMORY_BASIC_INFORMATION>& memories) {
    if (hProcess == nullptr) return false;
    // 初始化 vector 容量
    memories.clear();
    memories.reserve(200);
    // 获取 PageSize 和地址粒度
    SYSTEM_INFO sysInfo = { 0 };
    GetSystemInfo(&sysInfo);
    //遍历内存的指针p
    const char* p = (const char*)sysInfo.lpMinimumApplicationAddress;
    MEMORY_BASIC_INFORMATION  memInfo = { 0 };
    while (p < sysInfo.lpMaximumApplicationAddress) {
        // 获取进程虚拟内存块缓冲区字节数
        size_t size = VirtualQueryEx(
            hProcess,                                                                // 进程句柄
            p,                                                                                // 要查询内存块的基地址指针
            &memInfo,                                                                // 接收内存块信息的 MEMORY_BASIC_INFORMATION64 对象
            sizeof(MEMORY_BASIC_INFORMATION)                // 缓冲区大小
        );
        if (size != sizeof(MEMORY_BASIC_INFORMATION)) { break; }
        memories.push_back(memInfo);
        p += memInfo.RegionSize;
    }
    if (memories.size() == 0)
    {
        MessageBoxA(0, "枚举进程内存块时错误", "错误", MB_ICONWARNING | MB_TOPMOST | MB_OK);
    }
    return memories.size() > 0;
}

void PrintRegs()
{
    printf("rax = %016llx\n", rax);
    printf("rbx = %016llx\n", rbx);
    printf("rcx = %016llx\n", rcx);
    printf("rdx = %016llx\n", rdx);
    printf("rsi = %016llx\n", rsi);
    printf("rdi = %016llx\n", rdi);
    printf("rsp = %016llx\n", rsp);
    printf("rbp = %016llx\n", rbp);
    printf("r8 = %016llx\n", r8);
    printf("r9 = %016llx\n", r9);
    printf("r10 = %016llx\n", r10);
    printf("r11 = %016llx\n", r11);
    printf("r12 = %016llx\n", r12);
    printf("r13 = %016llx\n", r13);
    printf("r14 = %016llx\n", r14);
    printf("r15 = %016llx\n", r15);
    printf("rip = %016llx\n", rip);
    printf("rfl = %016llx\n", rfl);

}

void PrintStack()
{
    DWORD stack[10];
    uc_mem_read(uc, rsp, stack, 10 * sizeof(DWORD));
    for (int i = 0; i < 16; i++)
    {
        printf("%016llx+%02x | %08x |\n", rsp, 4*i, stack[i]);
    }
    printf("\n");
}

void ReadRegs()
{
    uc_reg_read(uc, UC_X86_REG_RAX, &rax);
    uc_reg_read(uc, UC_X86_REG_RBX, &rbx);
    uc_reg_read(uc, UC_X86_REG_RCX, &rcx);
    uc_reg_read(uc, UC_X86_REG_RDX, &rdx);
    uc_reg_read(uc, UC_X86_REG_RSI, &rsi);
    uc_reg_read(uc, UC_X86_REG_RDI, &rdi);
    uc_reg_read(uc, UC_X86_REG_RSP, &rsp);
    uc_reg_read(uc, UC_X86_REG_RBP, &rbp);
    uc_reg_read(uc, UC_X86_REG_R8, &r8);
    uc_reg_read(uc, UC_X86_REG_R9, &r9);
    uc_reg_read(uc, UC_X86_REG_R10, &r10);
    uc_reg_read(uc, UC_X86_REG_R11, &r11);
    uc_reg_read(uc, UC_X86_REG_R12, &r12);
    uc_reg_read(uc, UC_X86_REG_R13, &r13);
    uc_reg_read(uc, UC_X86_REG_R14, &r14);
    uc_reg_read(uc, UC_X86_REG_R15, &r15);
    uc_reg_read(uc, UC_X86_REG_RIP, &rip);
    uc_reg_read(uc, UC_X86_REG_RFLAGS, &rfl);
}

void WriteRegs()
{
    uc_reg_write(uc, UC_X86_REG_RAX, &rax);
    uc_reg_write(uc, UC_X86_REG_RBX, &rbx);
    uc_reg_write(uc, UC_X86_REG_RCX, &rcx);
    uc_reg_write(uc, UC_X86_REG_RDX, &rdx);
    uc_reg_write(uc, UC_X86_REG_RSI, &rsi);
    uc_reg_write(uc, UC_X86_REG_RDI, &rdi);
    uc_reg_write(uc, UC_X86_REG_RSP, &rsp);
    uc_reg_write(uc, UC_X86_REG_RBP, &rbp);
    uc_reg_write(uc, UC_X86_REG_R8, &r8);
    uc_reg_write(uc, UC_X86_REG_R9, &r9);
    uc_reg_write(uc, UC_X86_REG_R10, &r10);
    uc_reg_write(uc, UC_X86_REG_R11, &r11);
    uc_reg_write(uc, UC_X86_REG_R12, &r12);
    uc_reg_write(uc, UC_X86_REG_R13, &r13);
    uc_reg_write(uc, UC_X86_REG_R14, &r14);
    uc_reg_write(uc, UC_X86_REG_R15, &r15);
    uc_reg_write(uc, UC_X86_REG_RIP, &rip);
    uc_reg_write(uc, UC_X86_REG_RFLAGS, &rfl);
}

uint64_t GetReg(const x86_reg& reg)
{
    uint64_t value = 0;
    switch (reg)
    {
        case X86_REG_RAX:uc_reg_read(uc, UC_X86_REG_RAX, &value);break;
        case X86_REG_RBX:uc_reg_read(uc, UC_X86_REG_RBX, &value);break;
        case X86_REG_RCX:uc_reg_read(uc, UC_X86_REG_RCX, &value);break;
        case X86_REG_RDX:uc_reg_read(uc, UC_X86_REG_RDX, &value);break;
        case X86_REG_RSI:uc_reg_read(uc, UC_X86_REG_RSI, &value);break;
        case X86_REG_RDI:uc_reg_read(uc, UC_X86_REG_RDI, &value);break;
        case X86_REG_RIP:uc_reg_read(uc, UC_X86_REG_RIP, &value);break;
        case X86_REG_EFLAGS:uc_reg_read(uc, UC_X86_REG_RFLAGS, &value);break;
        case X86_REG_RSP:uc_reg_read(uc, UC_X86_REG_RSP, &value);break;
        case X86_REG_RBP:uc_reg_read(uc, UC_X86_REG_RBP, &value);break;
        case X86_REG_R8:uc_reg_read(uc, UC_X86_REG_R8, &value);break;
        case X86_REG_R9:uc_reg_read(uc, UC_X86_REG_R9, &value);break;
        case X86_REG_R10:uc_reg_read(uc, UC_X86_REG_R10, &value);break;
        case X86_REG_R11:uc_reg_read(uc, UC_X86_REG_R11, &value);break;
        case X86_REG_R12:uc_reg_read(uc, UC_X86_REG_R12, &value);break;
        case X86_REG_R13:uc_reg_read(uc, UC_X86_REG_R13, &value);break;
        case X86_REG_R14:uc_reg_read(uc, UC_X86_REG_R14, &value);break;
        case X86_REG_R15:uc_reg_read(uc, UC_X86_REG_R15, &value);break;
        case X86_REG_EAX:uc_reg_read(uc, UC_X86_REG_EAX, &value);break;
        case X86_REG_EBX:uc_reg_read(uc, UC_X86_REG_EBX, &value);break;
        case X86_REG_ECX:uc_reg_read(uc, UC_X86_REG_ECX, &value);break;
        case X86_REG_EDX:uc_reg_read(uc, UC_X86_REG_EDX, &value);break;
        case X86_REG_ESI:uc_reg_read(uc, UC_X86_REG_RSI, &value); break;
        case X86_REG_EDI:uc_reg_read(uc, UC_X86_REG_RDI, &value); break;
        case X86_REG_EIP:uc_reg_read(uc, UC_X86_REG_RIP, &value); break;
        case X86_REG_ESP:uc_reg_read(uc, UC_X86_REG_RSP, &value); break;
        case X86_REG_EBP:uc_reg_read(uc, UC_X86_REG_RBP, &value); break;
        case X86_REG_R8D:uc_reg_read(uc, UC_X86_REG_R8, &value); break;
        case X86_REG_R9D:uc_reg_read(uc, UC_X86_REG_R9, &value); break;
        case X86_REG_R10D:uc_reg_read(uc, UC_X86_REG_R10, &value); break;
        case X86_REG_R11D:uc_reg_read(uc, UC_X86_REG_R11, &value); break;
        case X86_REG_R12D:uc_reg_read(uc, UC_X86_REG_R12, &value); break;
        case X86_REG_R13D:uc_reg_read(uc, UC_X86_REG_R13, &value); break;
        case X86_REG_R14D:uc_reg_read(uc, UC_X86_REG_R14, &value); break;
        case X86_REG_R15D:uc_reg_read(uc, UC_X86_REG_R15, &value); break;
        case X86_REG_AX:uc_reg_read(uc, UC_X86_REG_EAX, &value); break;
        case X86_REG_BX:uc_reg_read(uc, UC_X86_REG_EBX, &value); break;
        case X86_REG_CX:uc_reg_read(uc, UC_X86_REG_ECX, &value); break;
        case X86_REG_DX:uc_reg_read(uc, UC_X86_REG_EDX, &value); break;
        case X86_REG_SI:uc_reg_read(uc, UC_X86_REG_RSI, &value); break;
        case X86_REG_DI:uc_reg_read(uc, UC_X86_REG_RDI, &value); break;
        case X86_REG_IP:uc_reg_read(uc, UC_X86_REG_RIP, &value); break;
        case X86_REG_SP:uc_reg_read(uc, UC_X86_REG_RSP, &value); break;
        case X86_REG_BP:uc_reg_read(uc, UC_X86_REG_RBP, &value); break;
        case X86_REG_R8W:uc_reg_read(uc, UC_X86_REG_R8, &value); break;
        case X86_REG_R9W:uc_reg_read(uc, UC_X86_REG_R9, &value); break;
        case X86_REG_R10W:uc_reg_read(uc, UC_X86_REG_R10, &value); break;
        case X86_REG_R11W:uc_reg_read(uc, UC_X86_REG_R11, &value); break;
        case X86_REG_R12W:uc_reg_read(uc, UC_X86_REG_R12, &value); break;
        case X86_REG_R13W:uc_reg_read(uc, UC_X86_REG_R13, &value); break;
        case X86_REG_R14W:uc_reg_read(uc, UC_X86_REG_R14, &value); break;
        case X86_REG_R15W:uc_reg_read(uc, UC_X86_REG_R15, &value); break;
        default:assert(0);
    }
    return value;
}

bool ReadMemory(const uint64_t& addr, const DWORD& size, void* buf)
{
    uc_error = uc_mem_read(uc, addr, buf, size);
    if (uc_error != UC_ERR_OK) return false;
    return true;
}
uint64_t GetMemAddr(const x86_op_mem& mem)
{
    uint64_t addr = 0;
    if (mem.base != X86_REG_INVALID)
    {
        addr += GetReg(mem.base);
    }
    if (mem.index != X86_REG_INVALID)
    {
        addr += GetReg(mem.index) * mem.scale;
    }
    addr += mem.disp;
    return addr;
}
int main()
{
    uc_error = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
    if (uc_error != UC_ERR_OK) return -1;
    if (cs_open(CS_ARCH_X86, CS_MODE_64, &cshandle) != CS_ERR_OK)
        return -1;
    if (cs_option(cshandle, CS_OPT_DETAIL, CS_OPT_ON) !=CS_ERR_OK) 
        return -1;
    HANDLE hProcess = FindProcessByName("Project1.vmp.exe");
    if (hProcess == NULL)
    {
        printf("FindProcessByName failed\n");
        return -1;
    }
    vector<MEMORY_BASIC_INFORMATION> memories;
    my_EnumAllMemoryBlocks(hProcess, memories);
    for (int i = 0; i < memories.size(); ++i)
    {
        //if (memories[i].AllocationProtect == 0x00) continue;
        printf("0x%08x-0x%08x ", memories[i].BaseAddress, (DWORD)memories[i].BaseAddress + memories[i].RegionSize);
        DWORD oldProtect;
        if (!ReadProcessMemory(hProcess, memories[i].BaseAddress, Buffer, memories[i].RegionSize, NULL))
        {
            printf("err\n");
            continue;
        }
        uc_error = uc_mem_map(uc, (uint64_t)memories[i].BaseAddress, memories[i].RegionSize, UC_PROT_ALL);
        if (uc_error != UC_ERR_OK)
        {
            printf("uc_mem_map err ");
            continue;
        }
        uc_error = uc_mem_write(uc, (uint64_t)memories[i].BaseAddress, Buffer, memories[i].RegionSize);
        if (uc_error != UC_ERR_OK)
        {
            printf("uc_mem_write err ");
            continue;
        }
        printf("\n");
    }

    printf("Map success, monitor start.\n");
    DWORD run_cnt = 0;
    BYTE code[128];
    DWORD patch = 0x4;
    while(1)
    {
        WriteRegs();
        uc_error = uc_mem_read(uc, rip, code, 128);
        size_t count = cs_disasm(cshandle, code, 128, rip, 1, &insn);

        //printf("%016llx %s %s\n", rip, insn->mnemonic, insn->op_str);

        if (insn ->id == X86_INS_CPUID)
        {
            printf("[Special Insn] cpuid | %016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
        }
        else if (insn ->id == X86_INS_RDTSC)
        {
            printf("[Special Insn] rdtsc | %016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
        }
        else if (insn ->id == X86_INS_IN)
        {
            printf("[Special Insn] in | %016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
        }
        else if (insn->id == X86_INS_OUT)
        {
            printf("[Special Insn] out | %016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
        }
        else if (insn->id == X86_INS_SGDT)
        {
            printf("[Special Insn] sgdt | %016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
        }
        else if (insn->id == X86_INS_SLDT)
        {
            printf("[Special Insn] sldt | %016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
        }
        else if (insn->id == X86_INS_INT)
        {
            printf("[Special Insn] int | %016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
        }
        else if (insn->id == X86_INS_SYSENTER)
        {
            printf("[Special Insn] sysenter | %016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
        }
        else if (insn->id == X86_INS_SYSCALL)
        {
            printf("[Special Insn] syscall | %016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
            PrintRegs();
            PrintStack();
        }
        else if (insn->id != X86_INS_LEA)
        {
            for (DWORD i = 0; i < insn->detail->x86.op_count; i++)
            {
                if (insn->detail->x86.operands[i].type == X86_OP_MEM)
                {
                    uint64_t mem_addr = GetMemAddr(insn->detail->x86.operands[i].mem);
                    uint64_t value = 0;
                    if (mem_addr >= 0x10000 && mem_addr <= 0x200000) continue;
                    if (mem_addr >= 0x873000 && mem_addr <= 0x873000+0x427000 && i!=0) continue;
                    ReadMemory(mem_addr, insn->detail->x86.operands[i].size, &value);
                    printf("mem_addr = %016llx value = %016llx | %016llx %s %s\n", mem_addr, value, rip, insn->mnemonic, insn->op_str);
                    break;
                }
            }
        }
        cs_free(insn, 1);
        uc_error = uc_emu_start(uc, rip, 0xffffffff, 0, 1);
        if (uc_error) {
            printf("Exception with error returned %u: %s\n",uc_error, uc_strerror(uc_error));
            printf("%016llx %s %s\n", rip, insn->mnemonic, insn->op_str);
            PrintRegs();
            PrintStack();
            break;
        }
        
        run_cnt++;
        ReadRegs();
    }
    printf("run_cnt = %d\n", run_cnt);
    
}

免费评分

参与人数 26吾爱币 +27 热心值 +25 收起 理由
156608225 + 2 + 1 用心讨论,共获提升!
大白菜明媚太阳 + 1 + 1 谢谢@Thanks!
R00tkit + 1 + 1 我很赞同!
笙若 + 1 + 1 谢谢@Thanks!
hehe1337 + 1 用心讨论,共获提升!
X1a0 + 1 + 1 用心讨论,共获提升!
Marken888 + 1 + 1 用心讨论,共获提升!
aabbccli + 1 + 1 我很赞同!
1MajorTom1 + 1 热心回复!
netpune + 1 + 1 热心回复!
Chenda1 + 1 + 1 用心讨论,共获提升!
wangli2065 + 1 + 1 用心讨论,共获提升!
抱歉、 + 1 用心讨论,共获提升!
JiaXiaoShuai + 1 + 1 用心讨论,共获提升!
timeni + 1 + 1 用心讨论,共获提升!
ingsston + 1 + 1 热心回复!
hdLewis + 1 + 1 热心回复!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
sdaq1000 + 1 + 1 谢谢@Thanks!
youxiaxy + 1 + 1 我很赞同!
wangguang + 1 tql
成熟的美羊羊 + 2 + 1 帅起来了~
yp17792351859 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
忆魂丶天雷 + 2 + 1 我很赞同!
秋名山 + 1 + 1 谢谢@Thanks!
HongHu106 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2023-8-25 11:23
这个排版再处理一下就更好了,要么分段正文那别空格,标题加粗就行了,这样看的也能舒服,或者想空格可以用markdown来写也会好很多。
你与明日 发表于 2023-8-25 03:00
wow64程序可以无驱动自动过反调试,x64程序只能驱动了,不然每次找syscall麻烦到死.

而且windbg支持jmp far ,ret far,call far单步调试
waxiaoshuaiya 发表于 2023-8-25 08:08
only998 发表于 2023-8-25 08:36
感谢楼主分享~很有用
rjqg2023 发表于 2023-8-25 09:10
感谢分享教程,辛苦
15751011700 发表于 2023-8-25 09:15
谢谢分享!!!!
流泪的小白 发表于 2023-8-25 09:29
谢谢分享,学习到了
pandkai 发表于 2023-8-25 10:23
厉害,看不懂
j5ai2012 发表于 2023-8-25 11:30
看不得不是很懂,但还是学习下,谢谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-22 10:56

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表