nx_pe_compile_win_sw.nx source
↩ module page · 229 lines · 12579 B
1// nx_pe_compile_win_sw.nx -- W3b-4: an organ's REAL sys_write reaches WriteFile, fd-routed.
2//
3// W3b-3 (nx_pe_compile_win_write) proved a CUSTOM shim (nx_win_write) reaches WriteFile. This rung
4// redirects the GENUINE nx_syscalls name `sys_write` -- VERIFIED the compiler emits a direct
5// `call sys_write` (SysV rdi=fd, rsi=buf, rdx=n), the same redirectable label as any function. So an
6// organ that calls the real `sys_write(fd, buf, n)` prints natively on Windows, with fd routed to the
7// correct console handle (1->STD_OUTPUT, 2->STD_ERROR). No compiler or assembler edits.
8//
9// thunk (SysV in: rdi=fd, rsi=buf, rdx=n):
10// sub rsp, 0x38
11// mov [rsp+0x30], rdx ; save n (rdx MS-x64 VOLATILE)
12// mov ecx, -11 ; default STD_OUTPUT_HANDLE
13// cmp edi, 2 / jne +5 / mov ecx, -12 ; fd==2 -> STD_ERROR_HANDLE
14// call [rip+GetStdHandle] ; rax=handle; rsi(buf) survives (MS-x64 non-volatile)
15// mov rcx, rax / mov rdx, rsi / mov r8,[rsp+0x30] / lea r9,[rsp+0x28] / mov qword[rsp+0x20],0
16// call [rip+WriteFile]
17// add rsp, 0x38 / ret
18//
19// NO-FALSE-GREEN: an organ defining the canonical `sys_write` (body = __syscall(64,...), overwritten)
20// and calling sys_write(FD, "...", N). FD=1 -> the bytes land on STDOUT (stderr empty); FD=2 -> on
21// STDERR (stdout empty). Capturing the two streams separately proves the fd arg routes the handle
22// (a hardcoded-stdout thunk would fail FD=2). Tamper (corrupt WriteFile import) -> 0xC0000139.
23//
24// PIPELINE (build WSL sovereign, run native): src.nx
25// -> ./_offc/nx_compile_x86_native.elf <src> > /tmp/nxwin.s
26// -> ./_offc/nx_sov_build_run.elf nx_pe_compile_win_sw (reads /tmp/nxwin.s)
27// -> _offc/nx_win_compiled_sw.exe -> run native on Windows 11.
28//
29// HONEST SCOPE: redirecting sys_write makes WRITE-to-console work for an organ's genuine sys_write
30// call. A full I/O organ also calls sys_mmap/sys_exit/sys_read/etc. -- those still emit Linux
31// `syscall` (dead on Windows) and need the same label-redirect (if bodied) or a syscall-dispatch
32// layer. So this is NOT yet "any organ runs"; it is "the real sys_write name lowers to WriteFile,
33// fd-routed". Proven with a local sys_write definition; the imported nx_syscalls.sys_write is the
34// SAME label -> same redirect. Replicates keystone assemble (reuses axc_pass; no shared-assembler
35// edit). lineage_id: substrate_pe_compile_win_sw_v1
36
37import "nx_syscalls.nx"
38import "nxasm_x86.nx"
39import "nx_pe_writer.nx"
40
41const NXSW_CODE_CAP: i64 = 1048576
42const NXSW_FILE_SIZE: i64 = 0x800
43const NXSW_STUB_LEN: i64 = 18
44const NXSW_THUNK_LEN: i64 = 66 // fd-routed GetStdHandle+WriteFile returning thunk
45const NXSW_TEXT_CAP: i64 = 0x200
46const NXSW_RVA_TEXT: i64 = 0x1000
47const NXSW_RVA_RDATA: i64 = 0x2000
48const NXSW_RVA_IDATA: i64 = 0x3000
49const NXSW_FOFF_TEXT: i64 = 0x200
50const NXSW_FOFF_RDATA:i64 = 0x400
51const NXSW_FOFF_IDATA:i64 = 0x600
52const NXSW_IAT_GSH: i64 = 0x3048
53const NXSW_IAT_WF: i64 = 0x3050
54const NXSW_IAT_EXIT: i64 = 0x3058
55
56// Assemble; report `main` AND `sys_write` offsets (reuses axc_pass; no shared edit).
57func nxsw_assemble(src: *u8, n: i64, out: *u8, out_cap: i64, p_main: *i64, p_sw: *i64) -> i64 {
58 let lab_off: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
59 let lab_len: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
60 let lab_addr: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
61 let lab_sec: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
62 let op0: *i64 = sys_mmap(72) as *i64 // 9 slots for SIB (matches nxasm_x86)
63 let op1: *i64 = sys_mmap(72) as *i64
64 let op2: *i64 = sys_mmap(72) as *i64 // API DRIFT FIX: axc_pass gained op2
65 let scratch: *u8 = sys_mmap(64)
66 let posbox: *i64 = sys_mmap(16) as *i64
67 let n_lab_box: *i64 = sys_mmap(16) as *i64
68 n_lab_box[0] = 0
69 let lh: *i64 = sys_mmap(ASM_LH_SIZE * 8) as *i64
70
71 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)
72 if text_size < 0 { return text_size }
73 let n_lab: i64 = n_lab_box[0]
74
75 var main_a: i64 = 0 - 1
76 var sw_a: i64 = 0 - 1
77 var k: i64 = 0
78 while k < n_lab {
79 if lab_sec[k] == 1 { lab_addr[k] = lab_addr[k] + text_size }
80 if axc_tok_is(src, lab_off[k], lab_len[k], "main") == 1 { main_a = lab_addr[k] }
81 if axc_tok_is(src, lab_off[k], lab_len[k], "sys_write") == 1 { sw_a = lab_addr[k] }
82 k = k + 1
83 }
84 axc_lh_build(src, lab_off, lab_len, n_lab, lh)
85
86 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)
87 if total < 0 { return total }
88 if total > out_cap { return 0 - 200 }
89 p_main[0] = main_a
90 p_sw[0] = sw_a
91 return total
92}
93
94func nxsw_emit_pe(buf: *u8, code: *u8, code_len: i64, main_off: i64, sw_off: i64) -> i64 {
95 if (buf as i64) == 0 { return 0 - NX_PE_BAD_INPUT }
96 if sw_off < 0 { return 0 - NX_PE_BAD_INPUT }
97 let thunk_off: i64 = NXSW_STUB_LEN + code_len
98 let text_vsize: i64 = thunk_off + NXSW_THUNK_LEN
99 if text_vsize > NXSW_TEXT_CAP { return 0 - NX_PE_BAD_INPUT }
100
101 // ===== DOS + PE sig / COFF / Optional Header (W3b-1 3-import layout) =====
102 _w16(buf, 0, 0x5A4D)
103 _w32(buf, 0x3C, FOFF_PE_SIG)
104 _w32(buf, FOFF_PE_SIG, 0x00004550)
105 _w16(buf, FOFF_COFF + 0, PE_MACHINE_AMD64)
106 _w16(buf, FOFF_COFF + 2, 3)
107 _w16(buf, FOFF_COFF + 16, 0xF0)
108 _w16(buf, FOFF_COFF + 18, PE_CHAR_EXEC | PE_CHAR_LARGE_ADDR)
109 _w16(buf, FOFF_OPT + 0, PE_OH_MAGIC_PEPLUS)
110 _w8(buf, FOFF_OPT + 2, 1)
111 _w32(buf, FOFF_OPT + 4, 0x200)
112 _w32(buf, FOFF_OPT + 8, 0x400)
113 _w32(buf, FOFF_OPT + 16, NXSW_RVA_TEXT)
114 _w32(buf, FOFF_OPT + 20, NXSW_RVA_TEXT)
115 _w64(buf, FOFF_OPT + 24, IMG_BASE_LO, IMG_BASE_HI)
116 _w32(buf, FOFF_OPT + 32, 0x1000)
117 _w32(buf, FOFF_OPT + 36, 0x200)
118 _w16(buf, FOFF_OPT + 40, 6)
119 _w16(buf, FOFF_OPT + 48, 6)
120 _w32(buf, FOFF_OPT + 56, 0x4000)
121 _w32(buf, FOFF_OPT + 60, 0x200)
122 _w16(buf, FOFF_OPT + 68, PE_SUBSYSTEM_CONSOLE)
123 _w64(buf, FOFF_OPT + 72, 0x100000, 0)
124 _w64(buf, FOFF_OPT + 80, 0x1000, 0)
125 _w64(buf, FOFF_OPT + 88, 0x100000, 0)
126 _w64(buf, FOFF_OPT + 96, 0x1000, 0)
127 _w32(buf, FOFF_OPT + 108, 16)
128 _w32(buf, FOFF_OPT + 112 + 8, NXSW_RVA_IDATA)
129 _w32(buf, FOFF_OPT + 112 + 12, 0x28)
130 _emit_section_header(buf, FOFF_SECT_TBL, 46, 116, 101, 120, 116, 0, 0, 0, text_vsize, NXSW_RVA_TEXT, 0x200, NXSW_FOFF_TEXT, PE_SECT_CODE_X_R)
131 _emit_section_header(buf, FOFF_SECT_TBL + 40, 46, 114, 100, 97, 116, 97, 0, 0, 16, NXSW_RVA_RDATA, 0x200, NXSW_FOFF_RDATA, PE_SECT_DATA_R)
132 _emit_section_header(buf, FOFF_SECT_TBL + 80, 46, 105, 100, 97, 116, 97, 0, 0, 0xA1, NXSW_RVA_IDATA, 0x200, NXSW_FOFF_IDATA, PE_SECT_DATA_R)
133
134 // ===== .text: minimal entry stub (call main; exit with its return) =====
135 let t: i64 = NXSW_FOFF_TEXT
136 _w8(buf, t+0, 0x48); _w8(buf, t+1, 0x83); _w8(buf, t+2, 0xEC); _w8(buf, t+3, 0x28)
137 _w8(buf, t+4, 0xE8); _w32(buf, t+5, 0x9 + main_off)
138 _w8(buf, t+9, 0x89); _w8(buf, t+10, 0xC1)
139 _w8(buf, t+11, 0xFF); _w8(buf, t+12, 0x15); _w32(buf, t+13, NXSW_IAT_EXIT - (NXSW_RVA_TEXT + 17))
140 _w8(buf, t+17, 0xCC)
141 var i: i64 = 0
142 while i < code_len { buf[t + NXSW_STUB_LEN + i] = code[i]; i = i + 1 }
143
144 // ===== LINKER STEP: fd-routed GetStdHandle+WriteFile thunk + redirect sys_write =====
145 let thunk_rva: i64 = NXSW_RVA_TEXT + thunk_off
146 let th: i64 = NXSW_FOFF_TEXT + thunk_off
147 _w8(buf, th+0, 0x48); _w8(buf, th+1, 0x83); _w8(buf, th+2, 0xEC); _w8(buf, th+3, 0x38) // sub rsp,0x38
148 _w8(buf, th+4, 0x48); _w8(buf, th+5, 0x89); _w8(buf, th+6, 0x54); _w8(buf, th+7, 0x24); _w8(buf, th+8, 0x30) // mov [rsp+0x30],rdx
149 _w8(buf, th+9, 0xB9); _w8(buf, th+10, 0xF5); _w8(buf, th+11, 0xFF); _w8(buf, th+12, 0xFF); _w8(buf, th+13, 0xFF) // mov ecx,-11 (STDOUT)
150 _w8(buf, th+14, 0x83); _w8(buf, th+15, 0xFF); _w8(buf, th+16, 0x02) // cmp edi,2
151 _w8(buf, th+17, 0x75); _w8(buf, th+18, 0x05) // jne +5 (skip mov ecx,-12)
152 _w8(buf, th+19, 0xB9); _w8(buf, th+20, 0xF4); _w8(buf, th+21, 0xFF); _w8(buf, th+22, 0xFF); _w8(buf, th+23, 0xFF) // mov ecx,-12 (STDERR)
153 _w8(buf, th+24, 0xFF); _w8(buf, th+25, 0x15); _w32(buf, th+26, NXSW_IAT_GSH - (thunk_rva + 30)) // call [rip] GetStdHandle
154 _w8(buf, th+30, 0x48); _w8(buf, th+31, 0x89); _w8(buf, th+32, 0xC1) // mov rcx,rax
155 _w8(buf, th+33, 0x48); _w8(buf, th+34, 0x89); _w8(buf, th+35, 0xF2) // mov rdx,rsi
156 _w8(buf, th+36, 0x4C); _w8(buf, th+37, 0x8B); _w8(buf, th+38, 0x44); _w8(buf, th+39, 0x24); _w8(buf, th+40, 0x30) // mov r8,[rsp+0x30]
157 _w8(buf, th+41, 0x4C); _w8(buf, th+42, 0x8D); _w8(buf, th+43, 0x4C); _w8(buf, th+44, 0x24); _w8(buf, th+45, 0x28) // lea r9,[rsp+0x28]
158 _w8(buf, th+46, 0x48); _w8(buf, th+47, 0xC7); _w8(buf, th+48, 0x44); _w8(buf, th+49, 0x24); _w8(buf, th+50, 0x20); _w32(buf, th+51, 0) // mov qword[rsp+0x20],0
159 _w8(buf, th+55, 0xFF); _w8(buf, th+56, 0x15); _w32(buf, th+57, NXSW_IAT_WF - (thunk_rva + 61)) // call [rip] WriteFile
160 _w8(buf, th+61, 0x48); _w8(buf, th+62, 0x83); _w8(buf, th+63, 0xC4); _w8(buf, th+64, 0x38) // add rsp,0x38
161 _w8(buf, th+65, 0xC3) // ret
162 // OVERWRITE sys_write's first 5 bytes with `jmp rel32` -> thunk.
163 let sw_rva: i64 = NXSW_RVA_TEXT + NXSW_STUB_LEN + sw_off
164 let sw: i64 = NXSW_FOFF_TEXT + NXSW_STUB_LEN + sw_off
165 _w8(buf, sw+0, 0xE9); _w32(buf, sw+1, thunk_rva - (sw_rva + 5))
166
167 // ===== .idata: 3 kernel32 imports (GetStdHandle, WriteFile, ExitProcess) -- W3b-1 layout =====
168 let d: i64 = NXSW_FOFF_IDATA
169 _w32(buf, d + 0, 0x3028)
170 _w32(buf, d + 12, 0x3092)
171 _w32(buf, d + 16, 0x3048)
172 _w64(buf, d + 0x28, 0x3068, 0)
173 _w64(buf, d + 0x30, 0x3078, 0)
174 _w64(buf, d + 0x38, 0x3084, 0)
175 _w64(buf, d + 0x40, 0, 0)
176 _w64(buf, d + 0x48, 0x3068, 0)
177 _w64(buf, d + 0x50, 0x3078, 0)
178 _w64(buf, d + 0x58, 0x3084, 0)
179 _w64(buf, d + 0x60, 0, 0)
180 _w16(buf, d + 0x68, 0)
181 _w8(buf,d+0x6A,71);_w8(buf,d+0x6B,101);_w8(buf,d+0x6C,116);_w8(buf,d+0x6D,83) // GetS
182 _w8(buf,d+0x6E,116);_w8(buf,d+0x6F,100);_w8(buf,d+0x70,72);_w8(buf,d+0x71,97) // tdHa
183 _w8(buf,d+0x72,110);_w8(buf,d+0x73,100);_w8(buf,d+0x74,108);_w8(buf,d+0x75,101) // ndle
184 _w8(buf,d+0x76,0);_w8(buf,d+0x77,0)
185 _w16(buf, d + 0x78, 0)
186 _w8(buf,d+0x7A,87);_w8(buf,d+0x7B,114);_w8(buf,d+0x7C,105);_w8(buf,d+0x7D,116) // Writ
187 _w8(buf,d+0x7E,101);_w8(buf,d+0x7F,70);_w8(buf,d+0x80,105);_w8(buf,d+0x81,108) // eFil
188 _w8(buf,d+0x82,101);_w8(buf,d+0x83,0) // e\0
189 _w16(buf, d + 0x84, 0)
190 _w8(buf,d+0x86,69);_w8(buf,d+0x87,120);_w8(buf,d+0x88,105);_w8(buf,d+0x89,116) // Exit
191 _w8(buf,d+0x8A,80);_w8(buf,d+0x8B,114);_w8(buf,d+0x8C,111);_w8(buf,d+0x8D,99) // Proc
192 _w8(buf,d+0x8E,101);_w8(buf,d+0x8F,115);_w8(buf,d+0x90,115);_w8(buf,d+0x91,0) // ess\0
193 _w8(buf,d+0x92,107);_w8(buf,d+0x93,101);_w8(buf,d+0x94,114);_w8(buf,d+0x95,110) // kern
194 _w8(buf,d+0x96,101);_w8(buf,d+0x97,108);_w8(buf,d+0x98,51);_w8(buf,d+0x99,50) // el32
195 _w8(buf,d+0x9A,46);_w8(buf,d+0x9B,100);_w8(buf,d+0x9C,108);_w8(buf,d+0x9D,108);_w8(buf,d+0x9E,0) // .dll\0
196
197 return NX_PE_OK
198}
199
200func main() -> i64 {
201 let lenbox: *i64 = sys_mmap(16) as *i64
202 let src: *u8 = sys_read_file("/tmp/nxwin.s" as *u8, lenbox)
203 if (src as i64) == 0 { return 1 }
204 let n: i64 = lenbox[0]
205 if n <= 0 { return 2 }
206
207 let code: *u8 = sys_mmap(NXSW_CODE_CAP)
208 let mainbox: *i64 = sys_mmap(16) as *i64
209 let swbox: *i64 = sys_mmap(16) as *i64
210 mainbox[0] = 0 - 1
211 swbox[0] = 0 - 1
212 let code_len: i64 = nxsw_assemble(src, n, code, NXSW_CODE_CAP, mainbox, swbox)
213 if code_len < 0 { return 3 }
214 let main_off: i64 = mainbox[0]
215 if main_off < 0 { return 4 }
216 let sw_off: i64 = swbox[0]
217 if sw_off < 0 { return 6 } // sys_write not found
218
219 let buf: *u8 = sys_mmap(NXSW_FILE_SIZE)
220 let rc: i64 = nxsw_emit_pe(buf, code, code_len, main_off, sw_off)
221 if rc != NX_PE_OK { return 5 }
222
223 let outp: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_offc/nx_win_compiled_sw.exe" as *u8
224 if nx_pe_write_to_file(outp, buf, NXSW_FILE_SIZE) != NX_PE_OK { return 70 }
225
226 let msg: *u8 = "[substrate] nxc2-compiled native real-sys_write PE written: nx_win_compiled_sw.exe\n" as *u8
227 sys_write(1, msg, 83)
228 return 0
229}