nx_pe_compile_win_wsa.nx source
↩ module page · 221 lines · 11183 B
1// nx_pe_compile_win_wsa.nx -- W-NET-0: a Nishi organ initializes Winsock (2-DLL PE import table).
2//
3// The network arc's foundation. Every prior organ imported ONLY kernel32; TCP sockets live in
4// ws2_32.dll, so a serving container needs a PE that imports from TWO DLLs. This rung proves the
5// 2-DLL import table + the first ws2_32 call (WSAStartup) -- native, no VM. Unlocks socket/bind/
6// listen/accept/recv/send (W-NET-1..) toward an HTTP server organ serving Elder UI on :5173.
7//
8// The keystone-linker redirects the genuine shim `nx_wsa_startup()` to a thunk that calls
9// ws2_32!WSAStartup. The thunk provides its OWN stack WSADATA buffer (so no allocator import needed):
10// nx_wsa_startup_thunk:
11// sub rsp, 0x228 ; 0x200 WSADATA + 0x28 shadow/align (rsp 8 mod16 -> 0x230 -> 0 mod16)
12// mov ecx, 0x0202 ; wVersionRequested = MAKEWORD(2,2)
13// lea rdx, [rsp+0x28] ; &WSADATA (above shadow)
14// call [rip+ws2_32!WSAStartup] ; rax = 0 on success
15// add rsp, 0x228 / ret
16//
17// 2 DLLs: kernel32 { ExitProcess } (entry-stub exit) + ws2_32 { WSAStartup }. IAT: ExitProcess 0x205C,
18// WSAStartup 0x206C.
19//
20// NO-FALSE-GREEN: source `{ let r = nx_wsa_startup(); return r + 70 }`. WSAStartup returns 0 on
21// success -> exit 70. If ws2_32 failed to bind, the OS loader fails (0xC0000139, exe won't run). So
22// exit 70 = Winsock genuinely initialized via the 2nd-DLL import. Tamper "WSAStartup"/"ws2_32.dll" ->
23// 0xC0000139 (proves the 2nd DLL is bound by the real OS).
24//
25// PIPELINE (build WSL sovereign, run native): src.nx -> nx_compile_x86_native.elf > /tmp/nxwin.s
26// -> nx_sov_build_run.elf nx_pe_compile_win_wsa -> _offc/nx_win_compiled_wsa.exe -> run native.
27//
28// HONEST SCOPE: WSAStartup only (Winsock init); socket/bind/listen/accept/recv/send are the next
29// W-NET rungs. Replicates keystone assemble (reuses axc_pass; no shared edit).
30// lineage_id: substrate_pe_compile_win_wsa_v1
31
32import "nx_syscalls.nx"
33import "nxasm_x86.nx"
34import "nx_pe_writer.nx"
35
36const NXWSA_CODE_CAP: i64 = 1048576
37const NXWSA_FILE_SIZE: i64 = 0x600
38const NXWSA_STUB_LEN: i64 = 18
39const NXWSA_THUNK_LEN: i64 = 31
40const NXWSA_TEXT_CAP: i64 = 0x200
41const NXWSA_RVA_TEXT: i64 = 0x1000
42const NXWSA_RVA_IDATA: i64 = 0x2000
43const NXWSA_FOFF_TEXT: i64 = 0x200
44const NXWSA_FOFF_IDATA:i64 = 0x400
45const NXWSA_IAT_EXIT: i64 = 0x205C
46const NXWSA_IAT_WSA: i64 = 0x206C
47
48func nxwsa_assemble(src: *u8, n: i64, out: *u8, out_cap: i64, p_main: *i64, p_sh: *i64) -> i64 {
49 let lab_off: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
50 let lab_len: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
51 let lab_addr: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
52 let lab_sec: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
53 let op0: *i64 = sys_mmap(72) as *i64 // 9 slots for SIB (matches nxasm_x86)
54 let op1: *i64 = sys_mmap(72) as *i64
55 let op2: *i64 = sys_mmap(72) as *i64 // API DRIFT FIX: axc_pass gained op2
56 let scratch: *u8 = sys_mmap(64)
57 let posbox: *i64 = sys_mmap(16) as *i64
58 let n_lab_box: *i64 = sys_mmap(16) as *i64
59 n_lab_box[0] = 0
60 let lh: *i64 = sys_mmap(ASM_LH_SIZE * 8) as *i64
61
62 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)
63 if text_size < 0 { return text_size }
64 let n_lab: i64 = n_lab_box[0]
65
66 var main_a: i64 = 0 - 1
67 var sh_a: i64 = 0 - 1
68 var k: i64 = 0
69 while k < n_lab {
70 if lab_sec[k] == 1 { lab_addr[k] = lab_addr[k] + text_size }
71 if axc_tok_is(src, lab_off[k], lab_len[k], "main") == 1 { main_a = lab_addr[k] }
72 if axc_tok_is(src, lab_off[k], lab_len[k], "nx_wsa_startup") == 1 { sh_a = lab_addr[k] }
73 k = k + 1
74 }
75 axc_lh_build(src, lab_off, lab_len, n_lab, lh)
76
77 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)
78 if total < 0 { return total }
79 if total > out_cap { return 0 - 200 }
80 p_main[0] = main_a
81 p_sh[0] = sh_a
82 return total
83}
84
85func nxwsa_emit_pe(buf: *u8, code: *u8, code_len: i64, main_off: i64, sh_off: i64) -> i64 {
86 if (buf as i64) == 0 { return 0 - NX_PE_BAD_INPUT }
87 if sh_off < 0 { return 0 - NX_PE_BAD_INPUT }
88 let thunk_off: i64 = NXWSA_STUB_LEN + code_len
89 let text_vsize: i64 = thunk_off + NXWSA_THUNK_LEN
90 if text_vsize > NXWSA_TEXT_CAP { return 0 - NX_PE_BAD_INPUT }
91
92 _w16(buf, 0, 0x5A4D)
93 _w32(buf, 0x3C, FOFF_PE_SIG)
94 _w32(buf, FOFF_PE_SIG, 0x00004550)
95 _w16(buf, FOFF_COFF + 0, PE_MACHINE_AMD64)
96 _w16(buf, FOFF_COFF + 2, 2)
97 _w16(buf, FOFF_COFF + 16, 0xF0)
98 _w16(buf, FOFF_COFF + 18, PE_CHAR_EXEC | PE_CHAR_LARGE_ADDR)
99 _w16(buf, FOFF_OPT + 0, PE_OH_MAGIC_PEPLUS)
100 _w8(buf, FOFF_OPT + 2, 1)
101 _w32(buf, FOFF_OPT + 4, 0x200)
102 _w32(buf, FOFF_OPT + 8, 0x200)
103 _w32(buf, FOFF_OPT + 16, NXWSA_RVA_TEXT)
104 _w32(buf, FOFF_OPT + 20, NXWSA_RVA_TEXT)
105 _w64(buf, FOFF_OPT + 24, IMG_BASE_LO, IMG_BASE_HI)
106 _w32(buf, FOFF_OPT + 32, 0x1000)
107 _w32(buf, FOFF_OPT + 36, 0x200)
108 _w16(buf, FOFF_OPT + 40, 6)
109 _w16(buf, FOFF_OPT + 48, 6)
110 _w32(buf, FOFF_OPT + 56, 0x3000)
111 _w32(buf, FOFF_OPT + 60, 0x200)
112 _w16(buf, FOFF_OPT + 68, PE_SUBSYSTEM_CONSOLE)
113 _w64(buf, FOFF_OPT + 72, 0x100000, 0)
114 _w64(buf, FOFF_OPT + 80, 0x1000, 0)
115 _w64(buf, FOFF_OPT + 88, 0x100000, 0)
116 _w64(buf, FOFF_OPT + 96, 0x1000, 0)
117 _w32(buf, FOFF_OPT + 108, 16)
118 _w32(buf, FOFF_OPT + 112 + 8, NXWSA_RVA_IDATA)
119 _w32(buf, FOFF_OPT + 112 + 12, 0x3C) // Import Table size = 3 descriptors (kernel32 + ws2_32 + null)
120 _emit_section_header(buf, FOFF_SECT_TBL, 46, 116, 101, 120, 116, 0, 0, 0, text_vsize, NXWSA_RVA_TEXT, 0x200, NXWSA_FOFF_TEXT, PE_SECT_CODE_X_R)
121 _emit_section_header(buf, FOFF_SECT_TBL + 40, 46, 105, 100, 97, 116, 97, 0, 0, 0xB0, NXWSA_RVA_IDATA, 0x200, NXWSA_FOFF_IDATA, PE_SECT_DATA_R)
122
123 // ===== .text: entry stub (call main; exit with its return) =====
124 let t: i64 = NXWSA_FOFF_TEXT
125 _w8(buf, t+0, 0x48); _w8(buf, t+1, 0x83); _w8(buf, t+2, 0xEC); _w8(buf, t+3, 0x28)
126 _w8(buf, t+4, 0xE8); _w32(buf, t+5, 0x9 + main_off)
127 _w8(buf, t+9, 0x89); _w8(buf, t+10, 0xC1)
128 _w8(buf, t+11, 0xFF); _w8(buf, t+12, 0x15); _w32(buf, t+13, NXWSA_IAT_EXIT - (NXWSA_RVA_TEXT + 17))
129 _w8(buf, t+17, 0xCC)
130 var i: i64 = 0
131 while i < code_len { buf[t + NXWSA_STUB_LEN + i] = code[i]; i = i + 1 }
132
133 // ===== LINKER STEP: WSAStartup thunk (own stack WSADATA) + redirect nx_wsa_startup =====
134 let thunk_rva: i64 = NXWSA_RVA_TEXT + thunk_off
135 let th: i64 = NXWSA_FOFF_TEXT + thunk_off
136 _w8(buf, th+0, 0x48); _w8(buf, th+1, 0x81); _w8(buf, th+2, 0xEC); _w32(buf, th+3, 0x228) // sub rsp,0x228
137 _w8(buf, th+7, 0xB9); _w32(buf, th+8, 0x0202) // mov ecx,0x0202
138 _w8(buf, th+12, 0x48); _w8(buf, th+13, 0x8D); _w8(buf, th+14, 0x54); _w8(buf, th+15, 0x24); _w8(buf, th+16, 0x28) // lea rdx,[rsp+0x28]
139 _w8(buf, th+17, 0xFF); _w8(buf, th+18, 0x15); _w32(buf, th+19, NXWSA_IAT_WSA - (thunk_rva + 23)) // call [rip] WSAStartup
140 _w8(buf, th+23, 0x48); _w8(buf, th+24, 0x81); _w8(buf, th+25, 0xC4); _w32(buf, th+26, 0x228) // add rsp,0x228
141 _w8(buf, th+30, 0xC3) // ret
142 // OVERWRITE nx_wsa_startup's first 5 bytes with `jmp rel32` -> thunk
143 let sh_rva: i64 = NXWSA_RVA_TEXT + NXWSA_STUB_LEN + sh_off
144 let sh: i64 = NXWSA_FOFF_TEXT + NXWSA_STUB_LEN + sh_off
145 _w8(buf, sh+0, 0xE9); _w32(buf, sh+1, thunk_rva - (sh_rva + 5))
146
147 // ===== .idata: 2 DLLs (kernel32 {ExitProcess} + ws2_32 {WSAStartup}) =====
148 let d: i64 = NXWSA_FOFF_IDATA
149 // Import Descriptor[0] kernel32
150 _w32(buf, d + 0x00, 0x203C) // OFT -> INT_k
151 _w32(buf, d + 0x0C, 0x2097) // Name -> "kernel32.dll"
152 _w32(buf, d + 0x10, 0x205C) // FT -> IAT_k
153 // Import Descriptor[1] ws2_32
154 _w32(buf, d + 0x14, 0x204C) // OFT -> INT_w
155 _w32(buf, d + 0x20, 0x20A4) // Name -> "ws2_32.dll"
156 _w32(buf, d + 0x24, 0x206C) // FT -> IAT_w
157 // Descriptor[2] null (d+0x28..0x3C) -- already zero
158 // INT_k @ 0x203C
159 _w64(buf, d + 0x3C, 0x207C, 0) // -> ExitProcess name
160 _w64(buf, d + 0x44, 0, 0) // null
161 // INT_w @ 0x204C
162 _w64(buf, d + 0x4C, 0x208A, 0) // -> WSAStartup name
163 _w64(buf, d + 0x54, 0, 0) // null
164 // IAT_k @ 0x205C
165 _w64(buf, d + 0x5C, 0x207C, 0) // ExitProcess (IAT 0x205C)
166 _w64(buf, d + 0x64, 0, 0)
167 // IAT_w @ 0x206C
168 _w64(buf, d + 0x6C, 0x208A, 0) // WSAStartup (IAT 0x206C)
169 _w64(buf, d + 0x74, 0, 0)
170 // IMAGE_IMPORT_BY_NAME ExitProcess @ 0x207C
171 _w16(buf, d + 0x7C, 0)
172 _w8(buf,d+0x7E,69);_w8(buf,d+0x7F,120);_w8(buf,d+0x80,105);_w8(buf,d+0x81,116) // Exit
173 _w8(buf,d+0x82,80);_w8(buf,d+0x83,114);_w8(buf,d+0x84,111);_w8(buf,d+0x85,99) // Proc
174 _w8(buf,d+0x86,101);_w8(buf,d+0x87,115);_w8(buf,d+0x88,115);_w8(buf,d+0x89,0) // ess\0
175 // IMAGE_IMPORT_BY_NAME WSAStartup @ 0x208A
176 _w16(buf, d + 0x8A, 0)
177 _w8(buf,d+0x8C,87);_w8(buf,d+0x8D,83);_w8(buf,d+0x8E,65);_w8(buf,d+0x8F,83) // WSAS
178 _w8(buf,d+0x90,116);_w8(buf,d+0x91,97);_w8(buf,d+0x92,114);_w8(buf,d+0x93,116) // tart
179 _w8(buf,d+0x94,117);_w8(buf,d+0x95,112);_w8(buf,d+0x96,0) // up\0
180 // "kernel32.dll\0" @ 0x2097
181 _w8(buf,d+0x97,107);_w8(buf,d+0x98,101);_w8(buf,d+0x99,114);_w8(buf,d+0x9A,110) // kern
182 _w8(buf,d+0x9B,101);_w8(buf,d+0x9C,108);_w8(buf,d+0x9D,51);_w8(buf,d+0x9E,50) // el32
183 _w8(buf,d+0x9F,46);_w8(buf,d+0xA0,100);_w8(buf,d+0xA1,108);_w8(buf,d+0xA2,108);_w8(buf,d+0xA3,0) // .dll\0
184 // "ws2_32.dll\0" @ 0x20A4
185 _w8(buf,d+0xA4,119);_w8(buf,d+0xA5,115);_w8(buf,d+0xA6,50);_w8(buf,d+0xA7,95) // ws2_
186 _w8(buf,d+0xA8,51);_w8(buf,d+0xA9,50);_w8(buf,d+0xAA,46);_w8(buf,d+0xAB,100) // 32.d
187 _w8(buf,d+0xAC,108);_w8(buf,d+0xAD,108);_w8(buf,d+0xAE,0) // ll\0
188
189 return NX_PE_OK
190}
191
192func main() -> i64 {
193 let lenbox: *i64 = sys_mmap(16) as *i64
194 let src: *u8 = sys_read_file("/tmp/nxwin.s" as *u8, lenbox)
195 if (src as i64) == 0 { return 1 }
196 let n: i64 = lenbox[0]
197 if n <= 0 { return 2 }
198
199 let code: *u8 = sys_mmap(NXWSA_CODE_CAP)
200 let mainbox: *i64 = sys_mmap(16) as *i64
201 let shbox: *i64 = sys_mmap(16) as *i64
202 mainbox[0] = 0 - 1
203 shbox[0] = 0 - 1
204 let code_len: i64 = nxwsa_assemble(src, n, code, NXWSA_CODE_CAP, mainbox, shbox)
205 if code_len < 0 { return 3 }
206 let main_off: i64 = mainbox[0]
207 if main_off < 0 { return 4 }
208 let sh_off: i64 = shbox[0]
209 if sh_off < 0 { return 6 }
210
211 let buf: *u8 = sys_mmap(NXWSA_FILE_SIZE)
212 let rc: i64 = nxwsa_emit_pe(buf, code, code_len, main_off, sh_off)
213 if rc != NX_PE_OK { return 5 }
214
215 let outp: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_offc/nx_win_compiled_wsa.exe" as *u8
216 if nx_pe_write_to_file(outp, buf, NXWSA_FILE_SIZE) != NX_PE_OK { return 70 }
217
218 let msg: *u8 = "[substrate] nxc2-compiled native Winsock-init PE (2-DLL) written: nx_win_compiled_wsa.exe\n" as *u8
219 sys_write(1, msg, 89)
220 return 0
221}