c++ - 监控操作码

标签 c++ assembly opcode

我正在尝试监视函数操作码的汇编指令。我通过从内存中的函数中减去 stub 地址来获得以字节为单位的函数大小。我目前只在寻找 mov 指令。当我显示 currentByte 时,它​​只输出 Ú,其十六进制值为 0xDA,在汇编中为 FIADD http://ref.x86asm.net/coder32.html#xDA为什么没有mov指令显示?

#include <iostream>
#include <Windows.h>
#include <ctime>
#include <vector>

#define PUSH 0x50
#define POP  0x58
#define MOV  0xB8
#define NOP  0x90
#define ADD  0x01
#define AND  0x21
#define XOR  0x31
#define OR   0x09
#define SBB  0x19
#define SUB  0x29

using namespace std;

int add(int x, int y)
{
    int result;
    __asm
    {
        mov eax, x
        add eax, y
        mov result, eax
        xor eax, eax        
    }
    return result;
}

void stub() { return; }

DWORD GetFunctionSize(DWORD* functionStartAddress, DWORD* stub)
{
    DWORD dwOldProtect;
    DWORD *func, *stubAddr;

    func = (DWORD*)functionStartAddress;
    stubAddr = (DWORD*)stub;

    DWORD size = func - stubAddr;
    VirtualProtect(func, size, PAGE_EXECUTE_READWRITE, &dwOldProtect);
    return size;
}

void GetCurrentByte(PVOID function)
{
    vector<PBYTE> currByte;

    PBYTE pCurrentByte = (PBYTE)function;
    if (*pCurrentByte == MOV)
    {
        cout << "MOV instr.\n";
    }
    cout << *pCurrentByte;
    currByte.push_back(pCurrentByte);
}

int main()
{

    DWORD size = GetFunctionSize((DWORD*)&add, (DWORD*)&stub);

    for (int i = 0; i < size; i++)
    {
        GetCurrentByte(add);
    }
    system("pause");
    return 0;
}

最佳答案

Why does no mov instruction display?

如果您处于 Debug模式,您需要知道您向 GetCurrentDate(PVOID) 传递了一个错误的地址,这意味着您正在从一个错误的地址读取字节并且还有其他一些错误,解决这个问题的方法如下这些步骤:

首先,代码字节生成自:

mov eax, x       // code bytes: 8B 45 08
mov result, eax  // code bytes: 89 45 FC 

0x8B 和 0x89 是您应该在 add(int, int) 函数中查找的值。

其次,要获取 add(int, int) 函数的第一个字节的地址,我建议使用此函数:

#define ASM_CALL                0x000000E8
#define ASM_JMP                 0x000000E9
#define ASM_CALL_SIZE           0x00000001
#define ASM_CALL_FULL_SIZE      0x00000005

DWORD GetFuncAddress(DWORD funcAddress)
{
    BYTE calledAddress = *(BYTE*)funcAddress; 

    while (calledAddress == ASM_CALL || calledAddress == ASM_JMP) {
        funcAddress = funcAddress + *(DWORD*)(funcAddress + ASM_CALL_SIZE) + ASM_CALL_FULL_SIZE;
        calledAddress = *(BYTE*)funcAddress;
    }

    return funcAddress; // The address of the first byte of the function.
}

第三,我建议在您的 GetFunctionSize(DOWRD) 内部进行优化,因为您知道您的添加函数以单个返回结束:

return result; // code bytes: C3

为什么不循环抛出 add 函数的字节,这样当你找到一个等于 0xC3 的字节时,你最终会得到函数的确切大小(以字节为单位),这段代码会让事情变得清晰:

#define ASM_RET  0xC3

SIZE_T GetFunctionSize(DWORD functionAddress)
{
    SIZE_T funcSize = 0;
    // Loop thru func's bytes, and breaks when return byte found.
    while (*((PBYTE)functionAddress++) != RET)
        funcSize++; 

    return funcSize;
}

第四,GetCurrentByte(PVOID)函数需要一些维护,所以我建议:

#define ASM_MOV1                0x8B 
#define ASM_MOV2                0x89

VOID GetCurrentByte(DWORD functionAddress, UINT &index)
{
    BYTE tempByte = *((PBYTE)functionAddress + index);
    // search for bytes which contains a mov instruction:
    if (tempByte == ASM_MOV1 || tempByte == ASM_MOV2)
        cout << "MOV instr found at : " << hex << ((DWORD)functionAddress + index) << endl;

}

最后,完整的代码是这样的:

#include <iostream>
#include <Windows.h>


#define ASM_RET                 0xC3
#define ASM_MOV1                0x8B 
#define ASM_MOV2                0x89
#define ASM_CALL                0xE8
#define ASM_JMP                 0xE9
#define ASM_CALL_SIZE           0x01
#define ASM_CALL_FULL_SIZE      0x05

using namespace std;

INT add(INT x, INT y)
{
    int result;
    __asm
    {
        mov eax, x
        add eax, y
        mov result, eax
        xor eax, eax
    }
    return result;
}

DWORD GetFuncAddress(DWORD funcAddress)
{
    BYTE calledAddress = *(BYTE*)funcAddress;

    while (calledAddress == ASM_CALL || calledAddress == ASM_JMP) {
        funcAddress = funcAddress + *(DWORD*)(funcAddress + ASM_CALL_SIZE) + ASM_CALL_FULL_SIZE;
        calledAddress = *(BYTE*)funcAddress;
    }

    return funcAddress;
}

SIZE_T GetFunctionSize(DWORD functionAddress)
{
    SIZE_T funcSize = 0;

    while (*((PBYTE)functionAddress++) != ASM_RET)
    {
        funcSize++; 
    }

    return funcSize;
}


VOID GetCurrentByte(DWORD functionAddress, UINT &index)
{
    BYTE tempByte = *((PBYTE)functionAddress + index);

    if (tempByte == ASM_MOV1 || tempByte == ASM_MOV2)
        cout << "MOV instr found at : " << hex << ((DWORD)functionAddress + index) << endl;

}


INT main()
{

    DWORD funcAddress = GetFuncAddress((DWORD)add); // Get func address.

    SIZE_T size = GetFunctionSize(funcAddress); // Get func size (bytes).

    for (UINT i = 0; i < size; i++) // loop thru the function memory block.
    {
        GetCurrentByte(funcAddress, i);
    }


    system("pause");
    return 0;
}

如果您在函数中发现许多 MOV 指令,请不要感到惊讶,因为它们是编译器创建的。

Amrane Abdelkader。

关于c++ - 监控操作码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39044856/

相关文章:

c++ - 我正在寻找一种在 VS2012 中通过 NatVis 显示 UUID 的正确方法

c++ - 类型之间的转换

assembly - 如果 gnu 中的文件太大,则程序集失败

c - C 或 Assembly 中是否有可用的定点表示

c - 汇编mov指令后缀?

assembly - 如何手动解释操作码?

c++ - 如何指向链表中的下一个内存?

c++ - 在 C++ 中定义 Unicode 时映射格式说明符?

objective-c - 如何使用它在地址 0xaaaa 处用 909090 覆盖操作码 8b5508?

assembly - 如何汇编RISC-V指令集的RVC(压缩指令)扩展?