FireDragon91245
FireDragon91245

Reputation: 53

Windows API SetThreadContext does not set EFlags Carry Flag

Im trying to run machine code on windows for testing purposes,

i got a working prototype the only thing not working are EFlags

SetThreadContext seems to NOT apply EFlags to the thread correctly,

If i modify the EFlags in the CONTEXT Structure to include the carry flag cntx->EFlags |= 1; and apply it with SetThreadContext and set a breakpoint at the adress of the threads execution with gdb and dump the eflags using info registers eflags it does NOT include CF (Carry Flag)

My current Prototype:

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;
}

What i also have tryed is setting bit 1 additionaly (eflag |= 2) because i have read its reserved but no change

Im running

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

==

start:
adc R15, 0
jmp start

Expectet output that R15 is 1 (Carry Flag added then cleared, R15 will not change because its adding 0)

Actual Output: R15 is 0

Debugging:

put gdb breakpoint at adress of func dump EFlags, see CF (Carry Flag is not set)

(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 ]

As seen the c++ definetly set the carry flag corectly, but its not set in the actual thread

Thats my question WHY does SetThreadContext not set the carry flag corectly in the thread

Aditional Resources i have used:
x86 Flags
GetThreadContext
CreateThread
ResumeThread
SuspendThread
CloseHandle

Upvotes: 5

Views: 129

Answers (1)

RbMm
RbMm

Reputation: 33754

if you look for RIP from CONTREXT you can view that it point to ntdll.RtlUserThreadStart but not on your func. and RCX register is point to your func. so you set EFlags at ntdll.RtlUserThreadStart. before it call your func the EFlags of course will change to undefined state. so this and must not work.

however you not need pass EFlags as parameter to shellcode. you can direct call it. of if you want execute it and another thread, you can pass up to 3 parameters ( rcx, rdx, r8 in case x64) if execute it in apc callback or single parameter in rcx

Upvotes: 2

Related Questions