I fixed my loader not being able to handle TLS data. Now it can load and run a program like
#include <stdio.h>
#include <windows.h>
#define TLS_VAL 0xdeadbeef
__declspec(thread) int tls_val = TLS_VAL;
int main() {
printf("performing test\n");
if (tls_val != TLS_VAL) {
printf("wrong tls_val, got: %d (%x)\n", tls_val, tls_val);
return 1;
}
printf("all good\n");
}
It happens in this code
if let Some(dir) = pe.tls_data.map(|data| data.image_tls_directory) {
log::debug!(target: "pe::tls", "{:#X?}", dir);
let start = dir.start_address_of_raw_data as usize - pe.image_base as usize;
let end = dir.end_address_of_raw_data as usize - pe.image_base as usize;
let len = end - start;
let mut data = vec![0; len + dir.size_of_zero_fill as usize];
data.as_mut_ptr().copy_from(memory.index::<u8>(start), len);
let slot = TlsAlloc();
log::debug!(target: "pe::tls", "slot: {:X?}", slot);
let teb = {
let ptr: usize;
// Grab the address of the main thread's TEB
arch::asm!("mov {}, gs:[0x58]", out(reg) ptr);
ptr as *mut *mut u8
};
*teb.add(slot as usize) = data.leak().as_mut_ptr();
let index_address = dir.address_of_index - pe.image_base;
*memory.index(index_address as usize) = slot;
}
TLS feels hacky and weird.