我的目标是找出哪些双字节操作码会生成非法指令异常. 例如,操作码0F 0B UD2引发无效操作码异常.提供UD2指令用于软件测试以显式生成无效操作码.

Warning蛇油代码领先,因为我不熟悉Windows的内部 struct .

下面的代码分配一个具有读/写/执行权限的4K页面,并以UD2为起点try 确定所有可能的双字节操作码.

首先,它将两字节操作码复制到4K页面的最后两个字节

opcodes

然后执行它们并判断异常代码.

我认为执行最后两个页面字节要么

  1. 生成恰好为两个字节的非法异常EXCEPTION_ILLEGAL_INSTRUCTION.
  2. 当扩展到超过4K页面时,生成访问冲突EXCEPTION_ACCESS_VIOLATION.

运行下面的代码显示了有趣的指令以及许多未知数:

Illegal opcodes 0x0f 0x0b (error 0xc000001d)
ud2 - Generates an invalid opcode. 
   
Illegal opcodes 0x0f 0x37 (error 0xc000001d)
getsec - Exit authenticated code execution mode.

Illegal opcodes 0x0f 0xaa (error 0xc000001d)
rsm - Resume operation of interrupted program.

Question

黑客代码在这个操作码范围内运行得很好

正在执行操作码0x0f 0x0b...正在执行操作码0x0f 0xcb

直到它遇到这两个操作码

0x0f 0xcc业务互换Ep

似乎任何操作堆栈指针的操作都会导致问题,导致堆栈指针停留在这一点(点击Continue只会重复消息)

stuck

我try 将操作码执行移到它自己的线程中,因为它们有自己的堆栈,但没有帮助!

有没有办法保留堆栈指针RSPRBP,或者可能有一个简单的修复方法来解决它?

(使用M$Visual C++2019生成)

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <intrin.h>

// The UD2 (0x0F, 0x0B) instruction is guaranteed to generate an invalid opcode exception.

DWORD InstructionResult;

void ExecuteOpcodes(LPVOID mem)
{
    __try
    {
        // Execute opcodes...
        ((void(*)())((unsigned char*)mem + 0xFFE))();
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        InstructionResult = GetExceptionCode();
    }
}

int main()
{
    LPVOID mem = VirtualAlloc(NULL, 2, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    DWORD oldProtect = VirtualProtect(mem, 2, PAGE_EXECUTE_READWRITE, &oldProtect);

    // Start searching at the UD2 (0x0F, 0x0B) instruction which is guaranteed to generate an invalid opcode exception.
    for (int i = 15; i <= 255; i++)
    {
        for (int j = 11; j <= 255; j++)
        {
            // Write two byte opcodes at the 4K page end.
            *((unsigned char*)mem + 0xFFE) = i;
            *((unsigned char*)mem + 0xFFF) = j;

            printf("Executing opcodes 0x%02x 0x%02x\n",i,j);
            HANDLE hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ExecuteOpcodes, mem, 0, 0);
            WaitForSingleObject(hThread, INFINITE);
            CloseHandle(hThread);
            if (InstructionResult == EXCEPTION_ILLEGAL_INSTRUCTION)
            {
                printf("Illegal opcodes 0x%02x 0x%02x (error 0x%08x)\n", i, j, InstructionResult);
            }
        }
    }

    VirtualFree(mem, 0, MEM_RELEASE);

    return 0;
}

推荐答案

也许有一个简单的解决办法可以解决这个问题?

解决这个问题的Unix标准方法是在子进程中执行所有测试.

15年前,当我在Windows上工作时,创建子进程非常昂贵(缓慢).但由于您需要try 的64K字节组合较少,即使是速度较慢的机制也最多只需几个小时就能得到所有答案.

C++相关问答推荐

数据包未从DPDK端口传输到内核端口

为什么双重打印与C中的float具有不同的大小时具有相同的值?

Win32API Wizzard97 PropSheet_SetWizButton不工作

LibpCap禁用监视器模式(C、MacOS)

为什么我一直收到分段错误?

C语言编译阶段与翻译阶段的关系

`#if`条件中是否允许`sizeof`?

VS代码';S C/C++扩展称C23真关键字和假关键字未定义

无法在OpenGL上绘制三角形

如何在C中只对字符串(包含数字、单词等)中的数字进行重复操作?

为什么我从CSV文件中进行排序和搜索的代码没有显示数据的所有结果?

C:在编译时构建和使用字符串文字的预处理器宏?

可变宏不能编译

使用%f格式说明符打印整数值

某些EAX值的不同调用方的CPUID结果不一致

为什么我在我的代码中得到错误和退出代码-1073741819(0xC0000005),但如果我添加了一个不相关的打印语句,它仍然有效?

RISC-V GCC编译器错误编译ASM代码

不兼容的整数到指针转换传递';char';到类型';常量字符*

UEFI 应用程序中的计时器回调仅在 AMI BIOS 中挂起

使用 SDL2 的 C 程序中的内存泄漏