Windows API SetThreadContext 未设置 EFlags 进位标志

问题描述 投票:0回答:1

我正在尝试在 Windows 上运行机器代码以进行测试,

我有一个工作原型,唯一不工作的是 EFlags

SetThreadContext 似乎NOT 将 EFlags 正确应用到线程,

如果我修改 CONTEXT 结构中的 EFlags 以包含进位标志

cntx->EFlags |= 1;
并将其与 SetThreadContext 一起应用,并使用 gdb 在线程执行的地址处设置断点并使用
info registers eflags
转储 eflags,它不包括CF(携带旗帜)

我当前的原型:

typedef struct machine_code_t {
    char *machine_code;
    size_t machine_code_size;
} machine_code;

char code_adc[] = "\x49\x83\xD7\x00\xEB\xFA";

#define IM_CODE code_adc
int main(void) {
    CONTEXT *final_context = nullptr;
    HANDLE threadhndle = nullptr;
    CONTEXT *context = nullptr;
    machine_code machineCode = {.machine_code = IM_CODE, .machine_code_size = sizeof(IM_CODE)};
    
    auto func = reinterpret_cast<LPTHREAD_START_ROUTINE>(VirtualAlloc(nullptr, machineCode.machine_code_size,
                                                                      MEM_COMMIT | MEM_RESERVE,
                                                                      PAGE_EXECUTE_READWRITE));
    if (func == nullptr) {
        printf("VirtualAlloc failed\n");
        return 1;
    }
    if (std::memcpy(reinterpret_cast<void *>(func), machineCode.machine_code, machineCode.machine_code_size) ==
        nullptr) {
        printf("memcpy failed\n");
        return 1;
    }
    threadhndle = CreateThread(nullptr, 0, func, nullptr, CREATE_SUSPENDED, &g_targetThreadId);
    if (threadhndle == nullptr) {
        printf("CreateThread failed\n");
        return 1;
    }
    context = (CONTEXT *) calloc(1, sizeof(CONTEXT));
    if (context == nullptr) {
        printf("malloc failed\n");
        return 1;
    }
    context->ContextFlags = CONTEXT_ALL;
    if (GetThreadContext(threadhndle, context) == 0) {
        printf("GetThreadContext failed\n");
        goto clean;
    }
    context->EFlags |= 1; // Set the carry flag
    context->R14 = 100;
    context->ContextFlags = CONTEXT_ALL;
    if (SetThreadContext(threadhndle, context) == 0) {
        printf("SetThreadContext failed\n");
        goto clean;
    }
    if (ResumeThread(threadhndle) == -1) {
        printf("ResumeThread failed\n");
        goto clean;
    }
    Sleep(100);
    if (SuspendThread(threadhndle) == -1) {
        printf("SuspendThread failed\n");
        goto clean;
    }
    final_context = (CONTEXT *) calloc(1, sizeof(CONTEXT));
    if (final_context == nullptr) {
        printf("malloc failed\n");
        goto clean;
    }
    final_context->ContextFlags = CONTEXT_FULL;
    if (GetThreadContext(threadhndle, final_context) == 0) {
        printf("GetThreadContext failed\n");
        goto clean;
    }
    
    printf("Initial R15: %lld\n", context->R15);
    printf("Final R15: %lld\n", final_context->R15);
    
    clean:
    free(context);
    if (final_context != nullptr) free(final_context);
    if (threadhndle != nullptr) CloseHandle(threadhndle);
    if (func != nullptr) VirtualFree(reinterpret_cast<LPVOID>(func), 0, MEM_RELEASE);
    return 0;
}

我还尝试过额外设置位 1 (

eflag |= 2
),因为我已阅读其保留但没有更改

我在跑步

"\x49\x83\xD7\x00\xEB\xFA"

==

start:
adc R15, 0
jmp start

预计输出R15为1(进位标志加后清零,R15不会改变,因为加了0)

实际输出:R15为0

调试:

将 gdb 断点置于

func
地址 转储 EFlags,请参阅 CF(未设置进位标志)

(gdb) break *0x00..... //adress stored in func variable
// Wait for hit on breakpoint should show [New Thread ...] then hit the brakpoint
(gdb) x/i $pc // should show adc $0x0,%r15 (reversed in comparison to intel syntax but still correct)
(gdb) info registers eflags // should show something like [ PF ZF IF ]

正如所见,c++明确地设置了进位标志,但它没有在实际线程中设置

这就是我的问题为什么 SetThreadContext 没有在线程中正确设置进位标志

我使用过的其他资源:
x86 标志
获取ThreadContext
创建线程
恢复主题
挂起线程
关闭句柄

windows assembly winapi machine-code eflags
1个回答
0
投票

如果您从

RIP
查找
CONTREXT
,您可以看到它指向
ntdll.RtlUserThreadStart
,但不在您的
func
上。和
RCX
寄存器指向您的
func
。所以您将
EFlags
设置为
ntdll.RtlUserThreadStart
。在它调用您的
func
之前,
EFlags
当然会更改为未定义状态。所以这一定行不通。

但是您不需要将 EFlags 作为参数传递给 shellcode。你可以直接调用它。如果你想执行它和另一个线程,如果在 apc 回调中执行,或者在

rcx
 中执行单个参数,则最多可以传递 3 个参数( 
rdx
r8
rcx

,如果是 x64)
© www.soinside.com 2019 - 2024. All rights reserved.