code wiki / (root) / nx_pe_compile_win_mmap.nx

nx_pe_compile_win_mmap.nx source

↩ module page · 212 lines · 11064 B

1// nx_pe_compile_win_mmap.nx -- W3b-5a: an organ's REAL sys_mmap reaches VirtualAlloc. 2// 3// sys_mmap is the allocation primitive EVERY organ uses, so it is the gating syscall for running a 4// real organ native. W3b-4 redirected sys_write -> WriteFile; this redirects the genuine nx_syscalls 5// name `sys_mmap` -> a kernel32 VirtualAlloc thunk (VERIFIED the compiler emits a direct `call sys_mmap`, 6// SysV rdi=size). So a compiled organ's own sys_mmap(size) returns real, writable Windows memory. No 7// compiler or assembler edits. 8// 9// thunk (SysV in: rdi=size -> VirtualAlloc(NULL, size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)): 10// sub rsp, 0x28 ; shadow + 16-byte align (rsp 8 mod16 at entry -> 0x30 -> 0 mod16) 11// mov rdx, rdi ; arg2 dwSize = size 12// xor ecx, ecx ; arg1 lpAddress = NULL 13// mov r8d, 0x3000 ; arg3 MEM_COMMIT(0x1000)|MEM_RESERVE(0x2000) 14// mov r9d, 0x04 ; arg4 PAGE_READWRITE 15// call [rip+VirtualAlloc] 16// add rsp, 0x28 / ret ; rax = base pointer (SysV return) 17// 18// NO-FALSE-GREEN: source `{ let p = sys_mmap(4096); p[0]=77; p[1]=22; return p[0]+p[1] }`. Exit 99 19// proves VirtualAlloc returned a VALID, WRITABLE region and the compiled code wrote+read it back. A 20// NULL/fake pointer would fault on p[0]=77 (exit 0xC0000005), not 99. Tamper (corrupt VirtualAlloc 21// import name) -> 0xC0000139 (real OS binding). 22// 23// PIPELINE (build WSL sovereign, run native): src.nx 24// -> ./_offc/nx_compile_x86_native.elf <src> > /tmp/nxwin.s 25// -> ./_offc/nx_sov_build_run.elf nx_pe_compile_win_mmap (reads /tmp/nxwin.s) 26// -> _offc/nx_win_compiled_mmap.exe -> run native on Windows 11. 27// 28// HONEST SCOPE: single redirect (sys_mmap). The TABLE rung (W3b-5b) combines sys_write+sys_mmap+ 29// sys_exit in one organ so a multi-syscall organ runs native. 2 imports (VirtualAlloc, ExitProcess). 30// Replicates keystone assemble (reuses axc_pass; no shared edit). lineage_id: substrate_pe_compile_win_mmap_v1 31 32import "nx_syscalls.nx" 33import "nxasm_x86.nx" 34import "nx_pe_writer.nx" 35 36const NXMM_CODE_CAP: i64 = 1048576 37const NXMM_FILE_SIZE: i64 = 0x600 // headers + .text + .idata 38const NXMM_STUB_LEN: i64 = 18 39const NXMM_THUNK_LEN: i64 = 32 40const NXMM_TEXT_CAP: i64 = 0x200 41const NXMM_RVA_TEXT: i64 = 0x1000 42const NXMM_RVA_IDATA: i64 = 0x2000 43const NXMM_FOFF_TEXT: i64 = 0x200 44const NXMM_FOFF_IDATA:i64 = 0x400 45const NXMM_IAT_VA: i64 = 0x2040 // IAT VirtualAlloc RVA 46const NXMM_IAT_EXIT: i64 = 0x2048 // IAT ExitProcess RVA 47 48// Assemble; report `main` AND `sys_mmap` offsets (reuses axc_pass; no shared edit). 49func nxmm_assemble(src: *u8, n: i64, out: *u8, out_cap: i64, p_main: *i64, p_mm: *i64) -> i64 { 50 let lab_off: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 51 let lab_len: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 52 let lab_addr: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 53 let lab_sec: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 54 let op0: *i64 = sys_mmap(72) as *i64 // 9 slots for SIB (matches nxasm_x86) 55 let op1: *i64 = sys_mmap(72) as *i64 56 let op2: *i64 = sys_mmap(72) as *i64 // API DRIFT FIX: axc_pass gained op2 57 let scratch: *u8 = sys_mmap(64) 58 let posbox: *i64 = sys_mmap(16) as *i64 59 let n_lab_box: *i64 = sys_mmap(16) as *i64 60 n_lab_box[0] = 0 61 let lh: *i64 = sys_mmap(ASM_LH_SIZE * 8) as *i64 62 63 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) 64 if text_size < 0 { return text_size } 65 let n_lab: i64 = n_lab_box[0] 66 67 var main_a: i64 = 0 - 1 68 var mm_a: i64 = 0 - 1 69 var k: i64 = 0 70 while k < n_lab { 71 if lab_sec[k] == 1 { lab_addr[k] = lab_addr[k] + text_size } 72 if axc_tok_is(src, lab_off[k], lab_len[k], "main") == 1 { main_a = lab_addr[k] } 73 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_mmap") == 1 { mm_a = lab_addr[k] } 74 k = k + 1 75 } 76 axc_lh_build(src, lab_off, lab_len, n_lab, lh) 77 78 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) 79 if total < 0 { return total } 80 if total > out_cap { return 0 - 200 } 81 p_main[0] = main_a 82 p_mm[0] = mm_a 83 return total 84} 85 86func nxmm_emit_pe(buf: *u8, code: *u8, code_len: i64, main_off: i64, mm_off: i64) -> i64 { 87 if (buf as i64) == 0 { return 0 - NX_PE_BAD_INPUT } 88 if mm_off < 0 { return 0 - NX_PE_BAD_INPUT } 89 let thunk_off: i64 = NXMM_STUB_LEN + code_len 90 let text_vsize: i64 = thunk_off + NXMM_THUNK_LEN 91 if text_vsize > NXMM_TEXT_CAP { return 0 - NX_PE_BAD_INPUT } 92 93 // ===== DOS + PE sig / COFF (2 sections) / Optional Header ===== 94 _w16(buf, 0, 0x5A4D) 95 _w32(buf, 0x3C, FOFF_PE_SIG) 96 _w32(buf, FOFF_PE_SIG, 0x00004550) 97 _w16(buf, FOFF_COFF + 0, PE_MACHINE_AMD64) 98 _w16(buf, FOFF_COFF + 2, 2) 99 _w16(buf, FOFF_COFF + 16, 0xF0) 100 _w16(buf, FOFF_COFF + 18, PE_CHAR_EXEC | PE_CHAR_LARGE_ADDR) 101 _w16(buf, FOFF_OPT + 0, PE_OH_MAGIC_PEPLUS) 102 _w8(buf, FOFF_OPT + 2, 1) 103 _w32(buf, FOFF_OPT + 4, 0x200) 104 _w32(buf, FOFF_OPT + 8, 0x200) 105 _w32(buf, FOFF_OPT + 16, NXMM_RVA_TEXT) 106 _w32(buf, FOFF_OPT + 20, NXMM_RVA_TEXT) 107 _w64(buf, FOFF_OPT + 24, IMG_BASE_LO, IMG_BASE_HI) 108 _w32(buf, FOFF_OPT + 32, 0x1000) 109 _w32(buf, FOFF_OPT + 36, 0x200) 110 _w16(buf, FOFF_OPT + 40, 6) 111 _w16(buf, FOFF_OPT + 48, 6) 112 _w32(buf, FOFF_OPT + 56, 0x3000) 113 _w32(buf, FOFF_OPT + 60, 0x200) 114 _w16(buf, FOFF_OPT + 68, PE_SUBSYSTEM_CONSOLE) 115 _w64(buf, FOFF_OPT + 72, 0x100000, 0) 116 _w64(buf, FOFF_OPT + 80, 0x1000, 0) 117 _w64(buf, FOFF_OPT + 88, 0x100000, 0) 118 _w64(buf, FOFF_OPT + 96, 0x1000, 0) 119 _w32(buf, FOFF_OPT + 108, 16) 120 _w32(buf, FOFF_OPT + 112 + 8, NXMM_RVA_IDATA) 121 _w32(buf, FOFF_OPT + 112 + 12, 0x28) 122 _emit_section_header(buf, FOFF_SECT_TBL, 46, 116, 101, 120, 116, 0, 0, 0, text_vsize, NXMM_RVA_TEXT, 0x200, NXMM_FOFF_TEXT, PE_SECT_CODE_X_R) 123 _emit_section_header(buf, FOFF_SECT_TBL + 40, 46, 105, 100, 97, 116, 97, 0, 0, 0x83, NXMM_RVA_IDATA, 0x200, NXMM_FOFF_IDATA, PE_SECT_DATA_R) 124 125 // ===== .text: minimal entry stub (call main; exit with its return) ===== 126 let t: i64 = NXMM_FOFF_TEXT 127 _w8(buf, t+0, 0x48); _w8(buf, t+1, 0x83); _w8(buf, t+2, 0xEC); _w8(buf, t+3, 0x28) 128 _w8(buf, t+4, 0xE8); _w32(buf, t+5, 0x9 + main_off) 129 _w8(buf, t+9, 0x89); _w8(buf, t+10, 0xC1) 130 _w8(buf, t+11, 0xFF); _w8(buf, t+12, 0x15); _w32(buf, t+13, NXMM_IAT_EXIT - (NXMM_RVA_TEXT + 17)) 131 _w8(buf, t+17, 0xCC) 132 var i: i64 = 0 133 while i < code_len { buf[t + NXMM_STUB_LEN + i] = code[i]; i = i + 1 } 134 135 // ===== LINKER STEP: synthesize the VirtualAlloc thunk + redirect sys_mmap ===== 136 let thunk_rva: i64 = NXMM_RVA_TEXT + thunk_off 137 let th: i64 = NXMM_FOFF_TEXT + thunk_off 138 _w8(buf, th+0, 0x48); _w8(buf, th+1, 0x83); _w8(buf, th+2, 0xEC); _w8(buf, th+3, 0x28) // sub rsp,0x28 139 _w8(buf, th+4, 0x48); _w8(buf, th+5, 0x89); _w8(buf, th+6, 0xFA) // mov rdx,rdi (size) 140 _w8(buf, th+7, 0x31); _w8(buf, th+8, 0xC9) // xor ecx,ecx (NULL) 141 _w8(buf, th+9, 0x41); _w8(buf, th+10, 0xB8); _w8(buf, th+11, 0x00); _w8(buf, th+12, 0x30); _w8(buf, th+13, 0x00); _w8(buf, th+14, 0x00) // mov r8d,0x3000 142 _w8(buf, th+15, 0x41); _w8(buf, th+16, 0xB9); _w8(buf, th+17, 0x04); _w8(buf, th+18, 0x00); _w8(buf, th+19, 0x00); _w8(buf, th+20, 0x00) // mov r9d,0x04 143 _w8(buf, th+21, 0xFF); _w8(buf, th+22, 0x15); _w32(buf, th+23, NXMM_IAT_VA - (thunk_rva + 27)) // call [rip] VirtualAlloc 144 _w8(buf, th+27, 0x48); _w8(buf, th+28, 0x83); _w8(buf, th+29, 0xC4); _w8(buf, th+30, 0x28) // add rsp,0x28 145 _w8(buf, th+31, 0xC3) // ret 146 // OVERWRITE sys_mmap's first 5 bytes with `jmp rel32` -> thunk. 147 let mm_rva: i64 = NXMM_RVA_TEXT + NXMM_STUB_LEN + mm_off 148 let mm: i64 = NXMM_FOFF_TEXT + NXMM_STUB_LEN + mm_off 149 _w8(buf, mm+0, 0xE9); _w32(buf, mm+1, thunk_rva - (mm_rva + 5)) 150 151 // ===== .idata: 2 kernel32 imports (VirtualAlloc, ExitProcess) ===== 152 let d: i64 = NXMM_FOFF_IDATA 153 _w32(buf, d + 0, 0x2028) // OriginalFirstThunk = INT RVA 154 _w32(buf, d + 12, 0x2076) // Name = "kernel32.dll" RVA 155 _w32(buf, d + 16, 0x2040) // FirstThunk = IAT RVA 156 // INT (RVA 0x2028) 157 _w64(buf, d + 0x28, 0x2058, 0) // -> VirtualAlloc name 158 _w64(buf, d + 0x30, 0x2068, 0) // -> ExitProcess name 159 _w64(buf, d + 0x38, 0, 0) // null 160 // IAT (RVA 0x2040) -- loader overwrites 161 _w64(buf, d + 0x40, 0x2058, 0) 162 _w64(buf, d + 0x48, 0x2068, 0) 163 _w64(buf, d + 0x50, 0, 0) 164 // IMAGE_IMPORT_BY_NAME VirtualAlloc (RVA 0x2058) 165 _w16(buf, d + 0x58, 0) 166 _w8(buf,d+0x5A,86);_w8(buf,d+0x5B,105);_w8(buf,d+0x5C,114);_w8(buf,d+0x5D,116) // Virt 167 _w8(buf,d+0x5E,117);_w8(buf,d+0x5F,97);_w8(buf,d+0x60,108);_w8(buf,d+0x61,65) // ualA 168 _w8(buf,d+0x62,108);_w8(buf,d+0x63,108);_w8(buf,d+0x64,111);_w8(buf,d+0x65,99) // lloc 169 _w8(buf,d+0x66,0);_w8(buf,d+0x67,0) // \0 pad 170 // IMAGE_IMPORT_BY_NAME ExitProcess (RVA 0x2068) 171 _w16(buf, d + 0x68, 0) 172 _w8(buf,d+0x6A,69);_w8(buf,d+0x6B,120);_w8(buf,d+0x6C,105);_w8(buf,d+0x6D,116) // Exit 173 _w8(buf,d+0x6E,80);_w8(buf,d+0x6F,114);_w8(buf,d+0x70,111);_w8(buf,d+0x71,99) // Proc 174 _w8(buf,d+0x72,101);_w8(buf,d+0x73,115);_w8(buf,d+0x74,115);_w8(buf,d+0x75,0) // ess\0 175 // "kernel32.dll\0" (RVA 0x2076) 176 _w8(buf,d+0x76,107);_w8(buf,d+0x77,101);_w8(buf,d+0x78,114);_w8(buf,d+0x79,110) // kern 177 _w8(buf,d+0x7A,101);_w8(buf,d+0x7B,108);_w8(buf,d+0x7C,51);_w8(buf,d+0x7D,50) // el32 178 _w8(buf,d+0x7E,46);_w8(buf,d+0x7F,100);_w8(buf,d+0x80,108);_w8(buf,d+0x81,108);_w8(buf,d+0x82,0) // .dll\0 179 180 return NX_PE_OK 181} 182 183func main() -> i64 { 184 let lenbox: *i64 = sys_mmap(16) as *i64 185 let src: *u8 = sys_read_file("/tmp/nxwin.s" as *u8, lenbox) 186 if (src as i64) == 0 { return 1 } 187 let n: i64 = lenbox[0] 188 if n <= 0 { return 2 } 189 190 let code: *u8 = sys_mmap(NXMM_CODE_CAP) 191 let mainbox: *i64 = sys_mmap(16) as *i64 192 let mmbox: *i64 = sys_mmap(16) as *i64 193 mainbox[0] = 0 - 1 194 mmbox[0] = 0 - 1 195 let code_len: i64 = nxmm_assemble(src, n, code, NXMM_CODE_CAP, mainbox, mmbox) 196 if code_len < 0 { return 3 } 197 let main_off: i64 = mainbox[0] 198 if main_off < 0 { return 4 } 199 let mm_off: i64 = mmbox[0] 200 if mm_off < 0 { return 6 } // sys_mmap not found 201 202 let buf: *u8 = sys_mmap(NXMM_FILE_SIZE) 203 let rc: i64 = nxmm_emit_pe(buf, code, code_len, main_off, mm_off) 204 if rc != NX_PE_OK { return 5 } 205 206 let outp: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_offc/nx_win_compiled_mmap.exe" as *u8 207 if nx_pe_write_to_file(outp, buf, NXMM_FILE_SIZE) != NX_PE_OK { return 70 } 208 209 let msg: *u8 = "[substrate] nxc2-compiled native sys_mmap PE written: nx_win_compiled_mmap.exe\n" as *u8 210 sys_write(1, msg, 79) 211 return 0 212}