code wiki / (root) / nx_pe_natbw.nx

nx_pe_natbw.nx source

↩ module page · 416 lines · 25575 B

1// nx_pe_natbw.nx -- GENERAL sovereign native-Windows PE emitter. 2// Wraps a /tmp/nxwin.s (from the FULL compiler _offc/nx_compile_x86.elf, which 3// supports func types/pointers) into a native .exe, bridging Linux syscalls to 4// kernel32 by PATCHING the shim entries (jmp -> thunk). Dynamic linker-style 5// layout (.text raw = roundup(VirtualSize,0x1000) so .idata is contiguous). 6// 7// HAL bridged (8 kernel32 imports): 8// sys_mmap -> VirtualAlloc(NULL,size,MEM_COMMIT|MEM_RESERVE,PAGE_RW) [lazy/large-alloc safe] 9// sys_write -> GetStdHandle + WriteFile (fd 1/2 routed) 10// sys_exit -> ExitProcess 11// sys_thread_create -> CreateThread + MS-ABI->SysV trampoline (reads {fn,ctx}) 12// sys_openat_rd -> CreateFileA (GENERIC_READ, OPEN_EXISTING) 13// sys_read -> ReadFile (returns bytesRead) 14// sys_close -> CloseHandle 15// license_tier: ORIGINAL 16import "nx_syscalls.nx" 17import "nxasm_x86.nx" 18import "nx_pe_writer.nx" 19 20const NB_CODE_CAP: i64 = 4194304 // 4MB assembled-code scratch 21const NB_BUF_CAP: i64 = 8388608 // 8MB emit buffer (covers a ~1.5MB forward .text) 22const NB_STUB_LEN: i64 = 18 23const NB_RVA_TEXT: i64 = 0x1000 24const NB_FOFF_TEXT: i64 = 0x200 25// thunk lengths (bytes) -- see the emission below 26const NB_VALEN: i64 = 32 // VirtualAlloc (mmap) 27const NB_WLEN: i64 = 66 // GetStdHandle+WriteFile (write) 28const NB_ELEN: i64 = 13 // ExitProcess (exit) 29const NB_CTLEN: i64 = 47 // CreateThread 30const NB_TRLEN: i64 = 24 // trampoline 31const NB_CFLEN: i64 = 59 // CreateFileA (openat_rd) 32const NB_RFLEN: i64 = 55 // ReadFile (read) -- incl DWORD clamp of the count 33const NB_CHLEN: i64 = 18 // CloseHandle (close) 34const NB_MULEN: i64 = 3 // munmap -> no-op (xor eax,eax; ret); process exit frees all 35const NB_WALEN: i64 = 40 // sys_futex_wait -> WaitOnAddress(addr,&cmp,4,INFINITE) 36const NB_WKLEN: i64 = 18 // sys_futex_wake -> WakeByAddressAll(addr) 37const NB_NQLEN: i64 = 38 // sys_now_us -> QueryPerformanceCounter/10 (Win10/11 QPC = 10MHz = 10 ticks/us) 38 39// write hint(u16=0)+ASCII+NUL at buf[base+off], even-align, return next off. 40func nb_name(buf: *u8, base: i64, off: i64, s: *u8) -> i64 { 41 _w16(buf, base + off, 0) 42 var i: i64 = 0 43 while s[i] != (0 as u8) { _w8(buf, base + off + 2 + i, s[i] as i64); i = i + 1 } 44 _w8(buf, base + off + 2 + i, 0) 45 var nxt: i64 = off + 2 + i + 1 46 if (nxt - (nxt / 2) * 2) != 0 { nxt = nxt + 1 } 47 return nxt 48} 49// write plain ASCII+NUL, return next off. 50func nb_str(buf: *u8, base: i64, off: i64, s: *u8) -> i64 { 51 var i: i64 = 0 52 while s[i] != (0 as u8) { _w8(buf, base + off + i, s[i] as i64); i = i + 1 } 53 _w8(buf, base + off + i, 0) 54 return off + i + 1 55} 56 57func nb_assemble(src: *u8, n: i64, out: *u8, out_cap: i64, p: *i64) -> i64 { 58 // p[0..7] = main, mmap, write, exit, thread_create, openat_rd, read, close offsets 59 let lab_off: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 60 let lab_len: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 61 let lab_addr: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 62 let lab_sec: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 63 let op0: *i64 = sys_mmap(72) as *i64 // 9 slots for SIB (matches nxasm_x86) 64 let op1: *i64 = sys_mmap(72) as *i64 65 let op2: *i64 = sys_mmap(72) as *i64 // API DRIFT FIX: axc_pass gained op2 66 let scratch: *u8 = sys_mmap(64) 67 let posbox: *i64 = sys_mmap(16) as *i64 68 let n_lab_box: *i64 = sys_mmap(16) as *i64 69 n_lab_box[0] = 0 70 let lh: *i64 = sys_mmap(ASM_LH_SIZE * 8) as *i64 71 72 let text_size: i64 = axc_pass(src, n, out, 0, 0, lab_off, lab_len, lab_addr, lab_sec, n_lab_box, lh, op0, op1, op2, scratch, posbox) 73 if text_size < 0 { return text_size } 74 let n_lab: i64 = n_lab_box[0] 75 76 var q: i64 = 0 77 while q < 12 { p[q] = 0 - 1; q = q + 1 } 78 var k: i64 = 0 79 while k < n_lab { 80 if lab_sec[k] == 1 { lab_addr[k] = lab_addr[k] + text_size } 81 if axc_tok_is(src, lab_off[k], lab_len[k], "main") == 1 { p[0] = lab_addr[k] } 82 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_mmap") == 1 { p[1] = lab_addr[k] } 83 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_write") == 1 { p[2] = lab_addr[k] } 84 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_exit") == 1 { p[3] = lab_addr[k] } 85 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_thread_create") == 1 { p[4] = lab_addr[k] } 86 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_openat_rd") == 1 { p[5] = lab_addr[k] } 87 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_read") == 1 { p[6] = lab_addr[k] } 88 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_close") == 1 { p[7] = lab_addr[k] } 89 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_munmap") == 1 { p[8] = lab_addr[k] } 90 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_futex_wait") == 1 { p[9] = lab_addr[k] } 91 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_futex_wake") == 1 { p[10] = lab_addr[k] } 92 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_now_us") == 1 { p[11] = lab_addr[k] } 93 k = k + 1 94 } 95 axc_lh_build(src, lab_off, lab_len, n_lab, lh) 96 let total: i64 = axc_pass(src, n, out, text_size, 1, lab_off, lab_len, lab_addr, lab_sec, n_lab_box, lh, op0, op1, op2, scratch, posbox) 97 if total < 0 { return total } 98 if total > out_cap { return 0 - 200 } 99 return total 100} 101 102// patch a syscall shim entry (at code offset `off`) with jmp rel32 -> thunk at text offset `thunk_off`. 103func nb_patch(buf: *u8, off: i64, thunk_off: i64) -> i64 { 104 if off < 0 { return 0 } 105 let at: i64 = NB_FOFF_TEXT + NB_STUB_LEN + off 106 let at_rva: i64 = NB_RVA_TEXT + NB_STUB_LEN + off 107 _w8(buf, at + 0, 0xE9) 108 _w32(buf, at + 1, thunk_off - ((NB_STUB_LEN + off) + 5)) // rel to next instr (both text offsets; == thunk RVA - next RVA) 109 return 0 110} 111 112func nb_emit_pe(buf: *u8, code: *u8, code_len: i64, p: *i64, p_fsize: *i64) -> i64 { 113 if (buf as i64) == 0 { return 0 - NX_PE_BAD_INPUT } 114 if p[1] < 0 { return 0 - NX_PE_BAD_INPUT } // sys_mmap required 115 if p[2] < 0 { return 0 - NX_PE_BAD_INPUT } // sys_write required 116 if p[3] < 0 { return 0 - NX_PE_BAD_INPUT } // sys_exit required 117 118 // ---- .text thunk layout (after stub + code) ---- 119 let voff: i64 = NB_STUB_LEN + code_len 120 let woff: i64 = voff + NB_VALEN 121 let eoff: i64 = woff + NB_WLEN 122 let ctoff: i64 = eoff + NB_ELEN 123 let troff: i64 = ctoff + NB_CTLEN 124 let cfoff: i64 = troff + NB_TRLEN 125 let rfoff: i64 = cfoff + NB_CFLEN 126 let choff: i64 = rfoff + NB_RFLEN 127 let muoff: i64 = choff + NB_CHLEN 128 let waoff: i64 = muoff + NB_MULEN 129 let wkoff: i64 = waoff + NB_WALEN 130 let nqoff: i64 = wkoff + NB_WKLEN 131 let text_vsize: i64 = nqoff + NB_NQLEN 132 133 let text_raw: i64 = ((text_vsize + 0xFFF) / 0x1000) * 0x1000 134 let rva_idata: i64 = NB_RVA_TEXT + text_raw 135 let foff_idata: i64 = NB_FOFF_TEXT + text_raw 136 let size_image: i64 = 0x1000 + text_raw + 0x1000 137 let file_size: i64 = foff_idata + 0x200 138 if file_size > NB_BUF_CAP { return 0 - NX_PE_BAD_INPUT } 139 // IAT slots (11 imports), IAT base = rva_idata + 0x88 (INT 0x28 = 12 qwords: 11 names + null) 140 let iat_va: i64 = rva_idata + 0x88 141 let iat_gsh: i64 = rva_idata + 0x90 142 let iat_wf: i64 = rva_idata + 0x98 143 let iat_exit: i64 = rva_idata + 0xA0 144 let iat_ct: i64 = rva_idata + 0xA8 145 let iat_cf: i64 = rva_idata + 0xB0 146 let iat_rf: i64 = rva_idata + 0xB8 147 let iat_ch: i64 = rva_idata + 0xC0 148 let iat_wa: i64 = rva_idata + 0xC8 149 let iat_wba: i64 = rva_idata + 0xD0 150 let iat_qpc: i64 = rva_idata + 0xD8 151 152 // ---- headers ---- 153 _w16(buf, 0, 0x5A4D) 154 _w32(buf, 0x3C, FOFF_PE_SIG) 155 _w32(buf, FOFF_PE_SIG, 0x00004550) 156 _w16(buf, FOFF_COFF + 0, PE_MACHINE_AMD64) 157 _w16(buf, FOFF_COFF + 2, 2) 158 _w16(buf, FOFF_COFF + 16, 0xF0) 159 _w16(buf, FOFF_COFF + 18, PE_CHAR_EXEC | PE_CHAR_LARGE_ADDR) 160 _w16(buf, FOFF_OPT + 0, PE_OH_MAGIC_PEPLUS) 161 _w8(buf, FOFF_OPT + 2, 1) 162 _w32(buf, FOFF_OPT + 4, text_raw) 163 _w32(buf, FOFF_OPT + 8, 0x200) 164 _w32(buf, FOFF_OPT + 16, NB_RVA_TEXT) 165 _w32(buf, FOFF_OPT + 20, NB_RVA_TEXT) 166 _w64(buf, FOFF_OPT + 24, IMG_BASE_LO, IMG_BASE_HI) 167 _w32(buf, FOFF_OPT + 32, 0x1000) 168 _w32(buf, FOFF_OPT + 36, 0x200) 169 _w16(buf, FOFF_OPT + 40, 6) 170 _w16(buf, FOFF_OPT + 48, 6) 171 _w32(buf, FOFF_OPT + 56, size_image) 172 _w32(buf, FOFF_OPT + 60, 0x200) 173 _w16(buf, FOFF_OPT + 68, PE_SUBSYSTEM_CONSOLE) 174 _w64(buf, FOFF_OPT + 72, 0x1000000, 0) // SizeOfStackReserve = 16MB (Linux main stack is 8MB; 1MB overflows the deep forward call chain) 175 _w64(buf, FOFF_OPT + 80, 0x100000, 0) // SizeOfStackCommit = 1MB 176 _w64(buf, FOFF_OPT + 88, 0x100000, 0) 177 _w64(buf, FOFF_OPT + 96, 0x1000, 0) 178 _w32(buf, FOFF_OPT + 108, 16) 179 _w32(buf, FOFF_OPT + 112 + 8, rva_idata) 180 _w32(buf, FOFF_OPT + 112 + 12, 0x28) 181 _emit_section_header(buf, FOFF_SECT_TBL, 46, 116, 101, 120, 116, 0, 0, 0, text_vsize, NB_RVA_TEXT, text_raw, NB_FOFF_TEXT, PE_SECT_CODE_X_R | 0x80000000) // R+W+X: module-level mutable globals live in .text (e.g. g_q5repack_consts cache) -> must be writable 182 _emit_section_header(buf, FOFF_SECT_TBL + 40, 46, 105, 100, 97, 116, 97, 0, 0, 0x200, rva_idata, 0x200, foff_idata, PE_SECT_DATA_R) 183 184 // ---- .text entry stub: sub rsp,0x28; call main; mov ecx,eax; call [ExitProcess]; int3 ---- 185 let t: i64 = NB_FOFF_TEXT 186 _w8(buf, t+0, 0x48); _w8(buf, t+1, 0x83); _w8(buf, t+2, 0xEC); _w8(buf, t+3, 0x28) 187 _w8(buf, t+4, 0xE8); _w32(buf, t+5, 0x9 + p[0]) 188 _w8(buf, t+9, 0x89); _w8(buf, t+10, 0xC1) 189 _w8(buf, t+11, 0xFF); _w8(buf, t+12, 0x15); _w32(buf, t+13, iat_exit - (NB_RVA_TEXT + 17)) 190 _w8(buf, t+17, 0xCC) 191 var i: i64 = 0 192 while i < code_len { buf[t + NB_STUB_LEN + i] = code[i]; i = i + 1 } 193 194 // ---- VirtualAlloc thunk (sys_mmap) ---- 195 let vrva: i64 = NB_RVA_TEXT + voff 196 let v: i64 = NB_FOFF_TEXT + voff 197 _w8(buf, v+0, 0x48); _w8(buf, v+1, 0x83); _w8(buf, v+2, 0xEC); _w8(buf, v+3, 0x28) // sub rsp,0x28 198 _w8(buf, v+4, 0x31); _w8(buf, v+5, 0xC9) // xor ecx,ecx 199 _w8(buf, v+6, 0x48); _w8(buf, v+7, 0x89); _w8(buf, v+8, 0xFA) // mov rdx,rdi 200 _w8(buf, v+9, 0x41); _w8(buf, v+10, 0xB8); _w8(buf, v+11, 0x00); _w8(buf, v+12, 0x30); _w8(buf, v+13, 0x00); _w8(buf, v+14, 0x00) // mov r8d,0x3000 201 _w8(buf, v+15, 0x41); _w8(buf, v+16, 0xB9); _w8(buf, v+17, 0x04); _w8(buf, v+18, 0x00); _w8(buf, v+19, 0x00); _w8(buf, v+20, 0x00) // mov r9d,4 202 _w8(buf, v+21, 0xFF); _w8(buf, v+22, 0x15); _w32(buf, v+23, iat_va - (vrva + 27)) // call [VirtualAlloc] 203 _w8(buf, v+27, 0x48); _w8(buf, v+28, 0x83); _w8(buf, v+29, 0xC4); _w8(buf, v+30, 0x28) // add rsp,0x28 204 _w8(buf, v+31, 0xC3) 205 206 // ---- WRITE thunk (sys_write -> GetStdHandle + WriteFile) ---- 207 let wrva: i64 = NB_RVA_TEXT + woff 208 let w: i64 = NB_FOFF_TEXT + woff 209 _w8(buf, w+0, 0x48); _w8(buf, w+1, 0x83); _w8(buf, w+2, 0xEC); _w8(buf, w+3, 0x38) 210 _w8(buf, w+4, 0x48); _w8(buf, w+5, 0x89); _w8(buf, w+6, 0x54); _w8(buf, w+7, 0x24); _w8(buf, w+8, 0x30) 211 _w8(buf, w+9, 0xB9); _w8(buf, w+10, 0xF5); _w8(buf, w+11, 0xFF); _w8(buf, w+12, 0xFF); _w8(buf, w+13, 0xFF) 212 _w8(buf, w+14, 0x83); _w8(buf, w+15, 0xFF); _w8(buf, w+16, 0x02) 213 _w8(buf, w+17, 0x75); _w8(buf, w+18, 0x05) 214 _w8(buf, w+19, 0xB9); _w8(buf, w+20, 0xF4); _w8(buf, w+21, 0xFF); _w8(buf, w+22, 0xFF); _w8(buf, w+23, 0xFF) 215 _w8(buf, w+24, 0xFF); _w8(buf, w+25, 0x15); _w32(buf, w+26, iat_gsh - (wrva + 30)) 216 _w8(buf, w+30, 0x48); _w8(buf, w+31, 0x89); _w8(buf, w+32, 0xC1) 217 _w8(buf, w+33, 0x48); _w8(buf, w+34, 0x89); _w8(buf, w+35, 0xF2) 218 _w8(buf, w+36, 0x4C); _w8(buf, w+37, 0x8B); _w8(buf, w+38, 0x44); _w8(buf, w+39, 0x24); _w8(buf, w+40, 0x30) 219 _w8(buf, w+41, 0x4C); _w8(buf, w+42, 0x8D); _w8(buf, w+43, 0x4C); _w8(buf, w+44, 0x24); _w8(buf, w+45, 0x28) 220 _w8(buf, w+46, 0x48); _w8(buf, w+47, 0xC7); _w8(buf, w+48, 0x44); _w8(buf, w+49, 0x24); _w8(buf, w+50, 0x20); _w32(buf, w+51, 0) 221 _w8(buf, w+55, 0xFF); _w8(buf, w+56, 0x15); _w32(buf, w+57, iat_wf - (wrva + 61)) 222 _w8(buf, w+61, 0x48); _w8(buf, w+62, 0x83); _w8(buf, w+63, 0xC4); _w8(buf, w+64, 0x38) 223 _w8(buf, w+65, 0xC3) 224 225 // ---- EXIT thunk (sys_exit -> ExitProcess) ---- 226 let erva: i64 = NB_RVA_TEXT + eoff 227 let e: i64 = NB_FOFF_TEXT + eoff 228 _w8(buf, e+0, 0x89); _w8(buf, e+1, 0xF9) 229 _w8(buf, e+2, 0x48); _w8(buf, e+3, 0x83); _w8(buf, e+4, 0xEC); _w8(buf, e+5, 0x28) 230 _w8(buf, e+6, 0xFF); _w8(buf, e+7, 0x15); _w32(buf, e+8, iat_exit - (erva + 12)) 231 _w8(buf, e+12, 0xCC) 232 233 // ---- CreateThread thunk (sys_thread_create) ---- 234 let ctrva: i64 = NB_RVA_TEXT + ctoff 235 let ct: i64 = NB_FOFF_TEXT + ctoff 236 _w8(buf, ct+0, 0x48); _w8(buf, ct+1, 0x83); _w8(buf, ct+2, 0xEC); _w8(buf, ct+3, 0x38) 237 _w8(buf, ct+4, 0x31); _w8(buf, ct+5, 0xC9) 238 _w8(buf, ct+6, 0x31); _w8(buf, ct+7, 0xD2) 239 _w8(buf, ct+8, 0x4C); _w8(buf, ct+9, 0x8D); _w8(buf, ct+10, 0x05); _w32(buf, ct+11, troff - (ctoff + 15)) 240 _w8(buf, ct+15, 0x49); _w8(buf, ct+16, 0x89); _w8(buf, ct+17, 0xF9) 241 _w8(buf, ct+18, 0x48); _w8(buf, ct+19, 0xC7); _w8(buf, ct+20, 0x44); _w8(buf, ct+21, 0x24); _w8(buf, ct+22, 0x20); _w32(buf, ct+23, 0) 242 _w8(buf, ct+27, 0x48); _w8(buf, ct+28, 0xC7); _w8(buf, ct+29, 0x44); _w8(buf, ct+30, 0x24); _w8(buf, ct+31, 0x28); _w32(buf, ct+32, 0) 243 _w8(buf, ct+36, 0xFF); _w8(buf, ct+37, 0x15); _w32(buf, ct+38, iat_ct - (ctrva + 42)) 244 _w8(buf, ct+42, 0x48); _w8(buf, ct+43, 0x83); _w8(buf, ct+44, 0xC4); _w8(buf, ct+45, 0x38) 245 _w8(buf, ct+46, 0xC3) 246 247 // ---- trampoline (MS-ABI rcx={fn,ctx} -> SysV fn(ctx)) ---- 248 let tr: i64 = NB_FOFF_TEXT + troff 249 _w8(buf, tr+0, 0x56) 250 _w8(buf, tr+1, 0x57) 251 _w8(buf, tr+2, 0x48); _w8(buf, tr+3, 0x83); _w8(buf, tr+4, 0xEC); _w8(buf, tr+5, 0x28) 252 _w8(buf, tr+6, 0x48); _w8(buf, tr+7, 0x8B); _w8(buf, tr+8, 0x01) 253 _w8(buf, tr+9, 0x48); _w8(buf, tr+10, 0x8B); _w8(buf, tr+11, 0x79); _w8(buf, tr+12, 0x08) 254 _w8(buf, tr+13, 0xFF); _w8(buf, tr+14, 0xD0) 255 _w8(buf, tr+15, 0x48); _w8(buf, tr+16, 0x83); _w8(buf, tr+17, 0xC4); _w8(buf, tr+18, 0x28) 256 _w8(buf, tr+19, 0x5F) 257 _w8(buf, tr+20, 0x5E) 258 _w8(buf, tr+21, 0x31); _w8(buf, tr+22, 0xC0) 259 _w8(buf, tr+23, 0xC3) 260 261 // ---- CreateFileA thunk (sys_openat_rd) ---- 262 let cfrva: i64 = NB_RVA_TEXT + cfoff 263 let cf: i64 = NB_FOFF_TEXT + cfoff 264 _w8(buf, cf+0, 0x48); _w8(buf, cf+1, 0x83); _w8(buf, cf+2, 0xEC); _w8(buf, cf+3, 0x48) // sub rsp,0x48 265 _w8(buf, cf+4, 0x48); _w8(buf, cf+5, 0x89); _w8(buf, cf+6, 0xF9) // mov rcx,rdi (path) 266 _w8(buf, cf+7, 0xBA); _w8(buf, cf+8, 0x00); _w8(buf, cf+9, 0x00); _w8(buf, cf+10, 0x00); _w8(buf, cf+11, 0x80) // mov edx,0x80000000 267 _w8(buf, cf+12, 0x41); _w8(buf, cf+13, 0xB8); _w8(buf, cf+14, 0x01); _w8(buf, cf+15, 0x00); _w8(buf, cf+16, 0x00); _w8(buf, cf+17, 0x00) // mov r8d,1 268 _w8(buf, cf+18, 0x45); _w8(buf, cf+19, 0x31); _w8(buf, cf+20, 0xC9) // xor r9d,r9d 269 _w8(buf, cf+21, 0x48); _w8(buf, cf+22, 0xC7); _w8(buf, cf+23, 0x44); _w8(buf, cf+24, 0x24); _w8(buf, cf+25, 0x20); _w32(buf, cf+26, 3) // mov qword[rsp+0x20],3 270 _w8(buf, cf+30, 0x48); _w8(buf, cf+31, 0xC7); _w8(buf, cf+32, 0x44); _w8(buf, cf+33, 0x24); _w8(buf, cf+34, 0x28); _w32(buf, cf+35, 0x80) // mov qword[rsp+0x28],0x80 271 _w8(buf, cf+39, 0x48); _w8(buf, cf+40, 0xC7); _w8(buf, cf+41, 0x44); _w8(buf, cf+42, 0x24); _w8(buf, cf+43, 0x30); _w32(buf, cf+44, 0) // mov qword[rsp+0x30],0 272 _w8(buf, cf+48, 0xFF); _w8(buf, cf+49, 0x15); _w32(buf, cf+50, iat_cf - (cfrva + 54)) // call [CreateFileA] 273 _w8(buf, cf+54, 0x48); _w8(buf, cf+55, 0x83); _w8(buf, cf+56, 0xC4); _w8(buf, cf+57, 0x48) 274 _w8(buf, cf+58, 0xC3) 275 276 // ---- ReadFile thunk (sys_read) ---- 277 let rfrva: i64 = NB_RVA_TEXT + rfoff 278 let rf: i64 = NB_FOFF_TEXT + rfoff 279 _w8(buf, rf+0, 0x48); _w8(buf, rf+1, 0x83); _w8(buf, rf+2, 0xEC); _w8(buf, rf+3, 0x38) // sub rsp,0x38 280 _w8(buf, rf+4, 0x49); _w8(buf, rf+5, 0x89); _w8(buf, rf+6, 0xD0) // mov r8,rdx (n) 281 _w8(buf, rf+7, 0xB8); _w8(buf, rf+8, 0xFF); _w8(buf, rf+9, 0xFF); _w8(buf, rf+10, 0xFF); _w8(buf, rf+11, 0x7F) // mov eax,0x7FFFFFFF 282 _w8(buf, rf+12, 0x49); _w8(buf, rf+13, 0x39); _w8(buf, rf+14, 0xC0) // cmp r8,rax 283 _w8(buf, rf+15, 0x4C); _w8(buf, rf+16, 0x0F); _w8(buf, rf+17, 0x47); _w8(buf, rf+18, 0xC0) // cmova r8,rax (clamp count to DWORD-safe) 284 _w8(buf, rf+19, 0x48); _w8(buf, rf+20, 0x89); _w8(buf, rf+21, 0xF2) // mov rdx,rsi (buf) 285 _w8(buf, rf+22, 0x48); _w8(buf, rf+23, 0x89); _w8(buf, rf+24, 0xF9) // mov rcx,rdi (fd) 286 _w8(buf, rf+25, 0x4C); _w8(buf, rf+26, 0x8D); _w8(buf, rf+27, 0x4C); _w8(buf, rf+28, 0x24); _w8(buf, rf+29, 0x30) // lea r9,[rsp+0x30] 287 _w8(buf, rf+30, 0x48); _w8(buf, rf+31, 0xC7); _w8(buf, rf+32, 0x44); _w8(buf, rf+33, 0x24); _w8(buf, rf+34, 0x20); _w32(buf, rf+35, 0) // mov qword[rsp+0x20],0 288 _w8(buf, rf+39, 0xFF); _w8(buf, rf+40, 0x15); _w32(buf, rf+41, iat_rf - (rfrva + 45)) // call [ReadFile] 289 _w8(buf, rf+45, 0x48); _w8(buf, rf+46, 0x8B); _w8(buf, rf+47, 0x44); _w8(buf, rf+48, 0x24); _w8(buf, rf+49, 0x30) // mov rax,[rsp+0x30] 290 _w8(buf, rf+50, 0x48); _w8(buf, rf+51, 0x83); _w8(buf, rf+52, 0xC4); _w8(buf, rf+53, 0x38) 291 _w8(buf, rf+54, 0xC3) 292 293 // ---- CloseHandle thunk (sys_close) ---- 294 let chrva: i64 = NB_RVA_TEXT + choff 295 let ch: i64 = NB_FOFF_TEXT + choff 296 _w8(buf, ch+0, 0x48); _w8(buf, ch+1, 0x83); _w8(buf, ch+2, 0xEC); _w8(buf, ch+3, 0x28) 297 _w8(buf, ch+4, 0x48); _w8(buf, ch+5, 0x89); _w8(buf, ch+6, 0xF9) 298 _w8(buf, ch+7, 0xFF); _w8(buf, ch+8, 0x15); _w32(buf, ch+9, iat_ch - (chrva + 13)) 299 _w8(buf, ch+13, 0x48); _w8(buf, ch+14, 0x83); _w8(buf, ch+15, 0xC4); _w8(buf, ch+16, 0x28) 300 _w8(buf, ch+17, 0xC3) 301 302 // ---- munmap no-op thunk (xor eax,eax; ret) ---- 303 let mu: i64 = NB_FOFF_TEXT + muoff 304 _w8(buf, mu+0, 0x31); _w8(buf, mu+1, 0xC0) // xor eax,eax 305 _w8(buf, mu+2, 0xC3) // ret 306 307 // ---- WaitOnAddress thunk (sys_futex_wait: rdi=addr, rsi=seen) ---- 308 let warva: i64 = NB_RVA_TEXT + waoff 309 let wa: i64 = NB_FOFF_TEXT + waoff 310 _w8(buf, wa+0, 0x48); _w8(buf, wa+1, 0x83); _w8(buf, wa+2, 0xEC); _w8(buf, wa+3, 0x38) // sub rsp,0x38 311 _w8(buf, wa+4, 0x48); _w8(buf, wa+5, 0x89); _w8(buf, wa+6, 0x74); _w8(buf, wa+7, 0x24); _w8(buf, wa+8, 0x28) // mov [rsp+0x28],rsi (compare value=seen) 312 _w8(buf, wa+9, 0x48); _w8(buf, wa+10, 0x89); _w8(buf, wa+11, 0xF9) // mov rcx,rdi (Address=addr) 313 _w8(buf, wa+12, 0x48); _w8(buf, wa+13, 0x8D); _w8(buf, wa+14, 0x54); _w8(buf, wa+15, 0x24); _w8(buf, wa+16, 0x28) // lea rdx,[rsp+0x28] (CompareAddress) 314 _w8(buf, wa+17, 0x41); _w8(buf, wa+18, 0xB8); _w8(buf, wa+19, 0x04); _w8(buf, wa+20, 0x00); _w8(buf, wa+21, 0x00); _w8(buf, wa+22, 0x00) // mov r8d,4 (AddressSize) 315 _w8(buf, wa+23, 0x41); _w8(buf, wa+24, 0xB9); _w8(buf, wa+25, 0xFF); _w8(buf, wa+26, 0xFF); _w8(buf, wa+27, 0xFF); _w8(buf, wa+28, 0xFF) // mov r9d,-1 (INFINITE) 316 _w8(buf, wa+29, 0xFF); _w8(buf, wa+30, 0x15); _w32(buf, wa+31, iat_wa - (warva + 35)) // call [WaitOnAddress] 317 _w8(buf, wa+35, 0x48); _w8(buf, wa+36, 0x83); _w8(buf, wa+37, 0xC4); _w8(buf, wa+38, 0x38) // add rsp,0x38 318 _w8(buf, wa+39, 0xC3) 319 320 // ---- WakeByAddressAll thunk (sys_futex_wake: rdi=addr) ---- 321 let wkrva: i64 = NB_RVA_TEXT + wkoff 322 let wk: i64 = NB_FOFF_TEXT + wkoff 323 _w8(buf, wk+0, 0x48); _w8(buf, wk+1, 0x83); _w8(buf, wk+2, 0xEC); _w8(buf, wk+3, 0x28) // sub rsp,0x28 324 _w8(buf, wk+4, 0x48); _w8(buf, wk+5, 0x89); _w8(buf, wk+6, 0xF9) // mov rcx,rdi 325 _w8(buf, wk+7, 0xFF); _w8(buf, wk+8, 0x15); _w32(buf, wk+9, iat_wba - (wkrva + 13)) // call [WakeByAddressAll] 326 _w8(buf, wk+13, 0x48); _w8(buf, wk+14, 0x83); _w8(buf, wk+15, 0xC4); _w8(buf, wk+16, 0x28) // add rsp,0x28 327 _w8(buf, wk+17, 0xC3) 328 329 // ---- QueryPerformanceCounter thunk (sys_now_us -> QPC(&c)/10 = microseconds) ---- 330 let nqrva: i64 = NB_RVA_TEXT + nqoff 331 let nq: i64 = NB_FOFF_TEXT + nqoff 332 _w8(buf, nq+0, 0x48); _w8(buf, nq+1, 0x83); _w8(buf, nq+2, 0xEC); _w8(buf, nq+3, 0x38) // sub rsp,0x38 333 _w8(buf, nq+4, 0x48); _w8(buf, nq+5, 0x8D); _w8(buf, nq+6, 0x4C); _w8(buf, nq+7, 0x24); _w8(buf, nq+8, 0x28) // lea rcx,[rsp+0x28] 334 _w8(buf, nq+9, 0xFF); _w8(buf, nq+10, 0x15); _w32(buf, nq+11, iat_qpc - (nqrva + 15)) // call [QueryPerformanceCounter] 335 _w8(buf, nq+15, 0x48); _w8(buf, nq+16, 0x8B); _w8(buf, nq+17, 0x44); _w8(buf, nq+18, 0x24); _w8(buf, nq+19, 0x28) // mov rax,[rsp+0x28] (100ns ticks) 336 _w8(buf, nq+20, 0x48); _w8(buf, nq+21, 0xC7); _w8(buf, nq+22, 0xC1); _w8(buf, nq+23, 0x0A); _w8(buf, nq+24, 0x00); _w8(buf, nq+25, 0x00); _w8(buf, nq+26, 0x00) // mov rcx,10 337 _w8(buf, nq+27, 0x48); _w8(buf, nq+28, 0x31); _w8(buf, nq+29, 0xD2) // xor rdx,rdx 338 _w8(buf, nq+30, 0x48); _w8(buf, nq+31, 0xF7); _w8(buf, nq+32, 0xF1) // div rcx (rax = ticks/10 = microseconds) 339 _w8(buf, nq+33, 0x48); _w8(buf, nq+34, 0x83); _w8(buf, nq+35, 0xC4); _w8(buf, nq+36, 0x38) // add rsp,0x38 340 _w8(buf, nq+37, 0xC3) // ret 341 342 // ---- patch shims -> thunks ---- 343 nb_patch(buf, p[1], voff) // sys_mmap -> VirtualAlloc 344 nb_patch(buf, p[2], woff) // sys_write -> WriteFile 345 nb_patch(buf, p[3], eoff) // sys_exit -> ExitProcess 346 nb_patch(buf, p[4], ctoff) // sys_thread_create -> CreateThread 347 nb_patch(buf, p[5], cfoff) // sys_openat_rd -> CreateFileA 348 nb_patch(buf, p[6], rfoff) // sys_read -> ReadFile 349 nb_patch(buf, p[7], choff) // sys_close -> CloseHandle 350 nb_patch(buf, p[8], muoff) // sys_munmap -> no-op 351 nb_patch(buf, p[9], waoff) // sys_futex_wait -> WaitOnAddress 352 nb_patch(buf, p[10], wkoff) // sys_futex_wake -> WakeByAddressAll 353 nb_patch(buf, p[11], nqoff) // sys_now_us -> QueryPerformanceCounter (skipped if p[11]<0, i.e. gate doesn't call it) 354 355 // ---- .idata: 11 kernelbase imports (INT 0x28, IAT 0x88, names 0xE8) ---- 356 let d: i64 = foff_idata 357 var no: i64 = 0xE8 358 let o_va: i64 = no; no = nb_name(buf, d, no, "VirtualAlloc") 359 let o_gsh: i64 = no; no = nb_name(buf, d, no, "GetStdHandle") 360 let o_wf: i64 = no; no = nb_name(buf, d, no, "WriteFile") 361 let o_ex: i64 = no; no = nb_name(buf, d, no, "ExitProcess") 362 let o_ct: i64 = no; no = nb_name(buf, d, no, "CreateThread") 363 let o_cf: i64 = no; no = nb_name(buf, d, no, "CreateFileA") 364 let o_rf: i64 = no; no = nb_name(buf, d, no, "ReadFile") 365 let o_ch: i64 = no; no = nb_name(buf, d, no, "CloseHandle") 366 let o_wa: i64 = no; no = nb_name(buf, d, no, "WaitOnAddress") 367 let o_wk: i64 = no; no = nb_name(buf, d, no, "WakeByAddressAll") 368 let o_qpc: i64 = no; no = nb_name(buf, d, no, "QueryPerformanceCounter") 369 let o_k32: i64 = no; no = nb_str(buf, d, no, "kernelbase.dll") 370 // descriptor 371 _w32(buf, d + 0, rva_idata + 0x28) 372 _w32(buf, d + 12, rva_idata + o_k32) 373 _w32(buf, d + 16, rva_idata + 0x88) 374 // INT (0x28) + IAT (0x80): 10 name RVAs each, then null 375 _w64(buf, d + 0x28, rva_idata + o_va, 0); _w64(buf, d + 0x88, rva_idata + o_va, 0) 376 _w64(buf, d + 0x30, rva_idata + o_gsh, 0); _w64(buf, d + 0x90, rva_idata + o_gsh, 0) 377 _w64(buf, d + 0x38, rva_idata + o_wf, 0); _w64(buf, d + 0x98, rva_idata + o_wf, 0) 378 _w64(buf, d + 0x40, rva_idata + o_ex, 0); _w64(buf, d + 0xA0, rva_idata + o_ex, 0) 379 _w64(buf, d + 0x48, rva_idata + o_ct, 0); _w64(buf, d + 0xA8, rva_idata + o_ct, 0) 380 _w64(buf, d + 0x50, rva_idata + o_cf, 0); _w64(buf, d + 0xB0, rva_idata + o_cf, 0) 381 _w64(buf, d + 0x58, rva_idata + o_rf, 0); _w64(buf, d + 0xB8, rva_idata + o_rf, 0) 382 _w64(buf, d + 0x60, rva_idata + o_ch, 0); _w64(buf, d + 0xC0, rva_idata + o_ch, 0) 383 _w64(buf, d + 0x68, rva_idata + o_wa, 0); _w64(buf, d + 0xC8, rva_idata + o_wa, 0) 384 _w64(buf, d + 0x70, rva_idata + o_wk, 0); _w64(buf, d + 0xD0, rva_idata + o_wk, 0) 385 _w64(buf, d + 0x78, rva_idata + o_qpc, 0); _w64(buf, d + 0xD8, rva_idata + o_qpc, 0) 386 _w64(buf, d + 0x80, 0, 0); _w64(buf, d + 0xE0, 0, 0) 387 388 p_fsize[0] = file_size 389 return NX_PE_OK 390} 391 392func main() -> i64 { 393 let lenbox: *i64 = sys_mmap(16) as *i64 394 let src: *u8 = sys_read_file("/tmp/nxwin.s" as *u8, lenbox) 395 if (src as i64) == 0 { return 1 } 396 let n: i64 = lenbox[0] 397 if n <= 0 { return 2 } 398 399 let code: *u8 = sys_mmap(NB_CODE_CAP) 400 let p: *i64 = sys_mmap(12 * 8) as *i64 401 let code_len: i64 = nb_assemble(src, n, code, NB_CODE_CAP, p) 402 if code_len < 0 { return 3 } 403 if p[0] < 0 { return 4 } 404 405 let buf: *u8 = sys_mmap(NB_BUF_CAP) 406 let fsizebox: *i64 = sys_mmap(16) as *i64 407 fsizebox[0] = 0 408 let rc: i64 = nb_emit_pe(buf, code, code_len, p, fsizebox) 409 if rc != NX_PE_OK { return 5 } 410 let fsize: i64 = fsizebox[0] 411 412 let outp: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_offc/nx_natbw_probe.exe" as *u8 413 if nx_pe_write_to_file(outp, buf, fsize) != NX_PE_OK { return 70 } 414 sys_write(1, "[substrate] native PE (8-import HAL) written\n" as *u8, 45) 415 return 0 416}