nx_pe_compile_win_fread.nx source
↩ module page · 194 lines · 12145 B
1// nx_pe_compile_win_fread.nx -- W-NET-5a: native file reading (CreateFileA + ReadFile), the capability
2// needed to serve the REAL Elder ui/dist from disk on :5173. De-risk standalone before integrating into
3// the HTTP server. Reads C:/Users/elder/elder-ai-platform/ui/dist/index.html and returns its byte count.
4// kernel32 only { ExitProcess, GetProcessHeap, HeapAlloc, CreateFileA, ReadFile } -- 1 DLL, 5 funcs.
5// CreateFileA takes the ASCII path directly (Windows accepts forward slashes), no UTF-16 needed.
6// lineage_id: substrate_pe_compile_win_fread_v1
7import "nx_syscalls.nx"
8import "nxasm_x86.nx"
9import "nx_pe_writer.nx"
10
11const FR_CODE_CAP: i64 = 1048576
12const FR_FILE_SIZE: i64 = 0x800
13const FR_STUB_LEN: i64 = 18
14const FR_TEXT_CAP: i64 = 0x400
15const FR_RVA_TEXT: i64 = 0x1000
16const FR_RVA_IDATA: i64 = 0x2000
17const FR_FOFF_TEXT: i64 = 0x200
18const FR_FOFF_IDATA:i64 = 0x600
19const FR_IAT_EXIT: i64 = 0x2058
20const FR_IAT_GPH: i64 = 0x2060
21const FR_IAT_HA: i64 = 0x2068
22const FR_IAT_CFA: i64 = 0x2070
23const FR_IAT_RF: i64 = 0x2078
24const FR_L_HALLOC: i64 = 29
25const FR_L_FOPEN: i64 = 57
26const FR_L_FREAD: i64 = 42
27
28func fr_lbloff(src: *u8, lab_off: *i64, lab_len: *i64, lab_addr: *i64, n_lab: i64, nm: *u8) -> i64 {
29 var k: i64 = 0
30 while k < n_lab { if axc_tok_is(src, lab_off[k], lab_len[k], nm) == 1 { return lab_addr[k] } k = k + 1 }
31 return 0 - 1
32}
33
34func fr_assemble(src: *u8, n: i64, out: *u8, out_cap: i64, off: *i64) -> i64 {
35 let lab_off: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
36 let lab_len: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
37 let lab_addr: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
38 let lab_sec: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64
39 let op0: *i64 = sys_mmap(72) as *i64 // 9 slots for SIB (matches nxasm_x86)
40 let op1: *i64 = sys_mmap(72) as *i64
41 let op2: *i64 = sys_mmap(72) as *i64 // API DRIFT FIX: axc_pass gained op2
42 let scratch: *u8 = sys_mmap(64)
43 let posbox: *i64 = sys_mmap(16) as *i64
44 let n_lab_box: *i64 = sys_mmap(16) as *i64
45 n_lab_box[0] = 0
46 let lh: *i64 = sys_mmap(ASM_LH_SIZE * 8) as *i64
47 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)
48 if text_size < 0 { return text_size }
49 let n_lab: i64 = n_lab_box[0]
50 var k: i64 = 0
51 while k < n_lab { if lab_sec[k] == 1 { lab_addr[k] = lab_addr[k] + text_size } k = k + 1 }
52 axc_lh_build(src, lab_off, lab_len, n_lab, lh)
53 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)
54 if total < 0 { return total }
55 if total > out_cap { return 0 - 200 }
56 off[0] = fr_lbloff(src, lab_off, lab_len, lab_addr, n_lab, "main")
57 off[1] = fr_lbloff(src, lab_off, lab_len, lab_addr, n_lab, "sys_mmap")
58 off[2] = fr_lbloff(src, lab_off, lab_len, lab_addr, n_lab, "nx_fopen")
59 off[3] = fr_lbloff(src, lab_off, lab_len, lab_addr, n_lab, "nx_fread")
60 return total
61}
62
63func fr_redirect(buf: *u8, shim_off: i64, thunk_off: i64) -> i64 {
64 if shim_off < 0 { return 0 }
65 let shim_rva: i64 = FR_RVA_TEXT + FR_STUB_LEN + shim_off
66 let thunk_rva: i64 = FR_RVA_TEXT + thunk_off
67 let s: i64 = FR_FOFF_TEXT + FR_STUB_LEN + shim_off
68 _w8(buf, s+0, 0xE9); _w32(buf, s+1, thunk_rva - (shim_rva + 5))
69 return 0
70}
71
72func fr_emit_pe(buf: *u8, code: *u8, code_len: i64, off: *i64) -> i64 {
73 if (buf as i64) == 0 { return 0 - NX_PE_BAD_INPUT }
74 if off[0] < 0 { return 0 - NX_PE_BAD_INPUT }
75 let thalloc: i64 = FR_STUB_LEN + code_len
76 let tfopen: i64 = thalloc + FR_L_HALLOC
77 let tfread: i64 = tfopen + FR_L_FOPEN
78 let tend: i64 = tfread + FR_L_FREAD
79 if tend > FR_TEXT_CAP { return 0 - NX_PE_BAD_INPUT }
80
81 _w16(buf, 0, 0x5A4D); _w32(buf, 0x3C, FOFF_PE_SIG); _w32(buf, FOFF_PE_SIG, 0x00004550)
82 _w16(buf, FOFF_COFF + 0, PE_MACHINE_AMD64); _w16(buf, FOFF_COFF + 2, 2)
83 _w16(buf, FOFF_COFF + 16, 0xF0); _w16(buf, FOFF_COFF + 18, PE_CHAR_EXEC | PE_CHAR_LARGE_ADDR)
84 _w16(buf, FOFF_OPT + 0, PE_OH_MAGIC_PEPLUS); _w8(buf, FOFF_OPT + 2, 1)
85 _w32(buf, FOFF_OPT + 4, 0x400); _w32(buf, FOFF_OPT + 8, 0x200)
86 _w32(buf, FOFF_OPT + 16, FR_RVA_TEXT); _w32(buf, FOFF_OPT + 20, FR_RVA_TEXT)
87 _w64(buf, FOFF_OPT + 24, IMG_BASE_LO, IMG_BASE_HI)
88 _w32(buf, FOFF_OPT + 32, 0x1000); _w32(buf, FOFF_OPT + 36, 0x200)
89 _w16(buf, FOFF_OPT + 40, 6); _w16(buf, FOFF_OPT + 48, 6)
90 _w32(buf, FOFF_OPT + 56, 0x3000); _w32(buf, FOFF_OPT + 60, 0x200)
91 _w16(buf, FOFF_OPT + 68, PE_SUBSYSTEM_CONSOLE)
92 _w64(buf, FOFF_OPT + 72, 0x100000, 0); _w64(buf, FOFF_OPT + 80, 0x1000, 0)
93 _w64(buf, FOFF_OPT + 88, 0x100000, 0); _w64(buf, FOFF_OPT + 96, 0x1000, 0)
94 _w32(buf, FOFF_OPT + 108, 16)
95 _w32(buf, FOFF_OPT + 112 + 8, FR_RVA_IDATA); _w32(buf, FOFF_OPT + 112 + 12, 0x28)
96 _emit_section_header(buf, FOFF_SECT_TBL, 46, 116, 101, 120, 116, 0, 0, 0, tend, FR_RVA_TEXT, 0x400, FR_FOFF_TEXT, PE_SECT_CODE_X_R)
97 _emit_section_header(buf, FOFF_SECT_TBL + 40, 46, 105, 100, 97, 116, 97, 0, 0, 0xDB, FR_RVA_IDATA, 0x200, FR_FOFF_IDATA, PE_SECT_DATA_R)
98
99 // entry stub
100 let t: i64 = FR_FOFF_TEXT
101 _w8(buf, t+0, 0x48); _w8(buf, t+1, 0x83); _w8(buf, t+2, 0xEC); _w8(buf, t+3, 0x28)
102 _w8(buf, t+4, 0xE8); _w32(buf, t+5, 0x9 + off[0])
103 _w8(buf, t+9, 0x89); _w8(buf, t+10, 0xC1)
104 _w8(buf, t+11, 0xFF); _w8(buf, t+12, 0x15); _w32(buf, t+13, FR_IAT_EXIT - (FR_RVA_TEXT + 17))
105 _w8(buf, t+17, 0xCC)
106 var i: i64 = 0
107 while i < code_len { buf[t + FR_STUB_LEN + i] = code[i]; i = i + 1 }
108
109 // HALLOC thunk (sys_mmap -> GetProcessHeap+HeapAlloc)
110 var rva: i64 = FR_RVA_TEXT + thalloc
111 var a: i64 = FR_FOFF_TEXT + thalloc
112 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28)
113 _w8(buf,a+4,0xFF);_w8(buf,a+5,0x15);_w32(buf,a+6,FR_IAT_GPH-(rva+10))
114 _w8(buf,a+10,0x48);_w8(buf,a+11,0x89);_w8(buf,a+12,0xC1)
115 _w8(buf,a+13,0x31);_w8(buf,a+14,0xD2)
116 _w8(buf,a+15,0x49);_w8(buf,a+16,0x89);_w8(buf,a+17,0xF8)
117 _w8(buf,a+18,0xFF);_w8(buf,a+19,0x15);_w32(buf,a+20,FR_IAT_HA-(rva+24))
118 _w8(buf,a+24,0x48);_w8(buf,a+25,0x83);_w8(buf,a+26,0xC4);_w8(buf,a+27,0x28)
119 _w8(buf,a+28,0xC3)
120 // FOPEN thunk (nx_fopen(path) -> CreateFileA(path,GENERIC_READ,SHARE_READ,0,OPEN_EXISTING,NORMAL,0))
121 rva = FR_RVA_TEXT + tfopen; a = FR_FOFF_TEXT + tfopen
122 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x48) // sub rsp,0x48
123 _w8(buf,a+4,0x48);_w8(buf,a+5,0x89);_w8(buf,a+6,0xF9) // mov rcx,rdi (path)
124 _w8(buf,a+7,0xBA);_w8(buf,a+8,0x00);_w8(buf,a+9,0x00);_w8(buf,a+10,0x00);_w8(buf,a+11,0x80) // mov edx,0x80000000
125 _w8(buf,a+12,0x41);_w8(buf,a+13,0xB8);_w32(buf,a+14,1) // mov r8d,1 (FILE_SHARE_READ)
126 _w8(buf,a+18,0x45);_w8(buf,a+19,0x31);_w8(buf,a+20,0xC9) // xor r9d,r9d
127 _w8(buf,a+21,0xC7);_w8(buf,a+22,0x44);_w8(buf,a+23,0x24);_w8(buf,a+24,0x20);_w32(buf,a+25,3) // mov dword[rsp+0x20],3 OPEN_EXISTING
128 _w8(buf,a+29,0xC7);_w8(buf,a+30,0x44);_w8(buf,a+31,0x24);_w8(buf,a+32,0x28);_w32(buf,a+33,0x80) // mov dword[rsp+0x28],0x80 NORMAL
129 _w8(buf,a+37,0x48);_w8(buf,a+38,0xC7);_w8(buf,a+39,0x44);_w8(buf,a+40,0x24);_w8(buf,a+41,0x30);_w32(buf,a+42,0) // mov qword[rsp+0x30],0
130 _w8(buf,a+46,0xFF);_w8(buf,a+47,0x15);_w32(buf,a+48,FR_IAT_CFA-(rva+52)) // call [CreateFileA]
131 _w8(buf,a+52,0x48);_w8(buf,a+53,0x83);_w8(buf,a+54,0xC4);_w8(buf,a+55,0x48) // add rsp,0x48
132 _w8(buf,a+56,0xC3)
133 // FREAD thunk (nx_fread(h,buf,n) -> ReadFile(h,buf,n,&got,0); returns got)
134 rva = FR_RVA_TEXT + tfread; a = FR_FOFF_TEXT + tfread
135 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x38) // sub rsp,0x38
136 _w8(buf,a+4,0x48);_w8(buf,a+5,0x89);_w8(buf,a+6,0xF9) // mov rcx,rdi (h)
137 _w8(buf,a+7,0x49);_w8(buf,a+8,0x89);_w8(buf,a+9,0xD0) // mov r8,rdx (n)
138 _w8(buf,a+10,0x48);_w8(buf,a+11,0x89);_w8(buf,a+12,0xF2) // mov rdx,rsi (buf)
139 _w8(buf,a+13,0x4C);_w8(buf,a+14,0x8D);_w8(buf,a+15,0x4C);_w8(buf,a+16,0x24);_w8(buf,a+17,0x30) // lea r9,[rsp+0x30] (&got)
140 _w8(buf,a+18,0x48);_w8(buf,a+19,0xC7);_w8(buf,a+20,0x44);_w8(buf,a+21,0x24);_w8(buf,a+22,0x20);_w32(buf,a+23,0) // mov qword[rsp+0x20],0
141 _w8(buf,a+27,0xFF);_w8(buf,a+28,0x15);_w32(buf,a+29,FR_IAT_RF-(rva+33)) // call [ReadFile]
142 _w8(buf,a+33,0x8B);_w8(buf,a+34,0x44);_w8(buf,a+35,0x24);_w8(buf,a+36,0x30) // mov eax,[rsp+0x30] (got)
143 _w8(buf,a+37,0x48);_w8(buf,a+38,0x83);_w8(buf,a+39,0xC4);_w8(buf,a+40,0x38) // add rsp,0x38
144 _w8(buf,a+41,0xC3)
145
146 fr_redirect(buf, off[1], thalloc)
147 fr_redirect(buf, off[2], tfopen)
148 fr_redirect(buf, off[3], tfread)
149
150 // ===== .idata: kernel32 { ExitProcess, GetProcessHeap, HeapAlloc, CreateFileA, ReadFile } =====
151 let d: i64 = FR_FOFF_IDATA
152 _w32(buf,d+0x00,0x2028); _w32(buf,d+0x0C,0x20CE); _w32(buf,d+0x10,0x2058)
153 // INT @0x28
154 _w64(buf,d+0x28,0x2088,0); _w64(buf,d+0x30,0x2096,0); _w64(buf,d+0x38,0x20A8,0); _w64(buf,d+0x40,0x20B4,0); _w64(buf,d+0x48,0x20C2,0); _w64(buf,d+0x50,0,0)
155 // IAT @0x58
156 _w64(buf,d+0x58,0x2088,0); _w64(buf,d+0x60,0x2096,0); _w64(buf,d+0x68,0x20A8,0); _w64(buf,d+0x70,0x20B4,0); _w64(buf,d+0x78,0x20C2,0); _w64(buf,d+0x80,0,0)
157 // ExitProcess @0x88
158 _w16(buf,d+0x88,0);_w8(buf,d+0x8A,69);_w8(buf,d+0x8B,120);_w8(buf,d+0x8C,105);_w8(buf,d+0x8D,116);_w8(buf,d+0x8E,80);_w8(buf,d+0x8F,114);_w8(buf,d+0x90,111);_w8(buf,d+0x91,99);_w8(buf,d+0x92,101);_w8(buf,d+0x93,115);_w8(buf,d+0x94,115);_w8(buf,d+0x95,0)
159 // GetProcessHeap @0x96
160 _w16(buf,d+0x96,0);_w8(buf,d+0x98,71);_w8(buf,d+0x99,101);_w8(buf,d+0x9A,116);_w8(buf,d+0x9B,80);_w8(buf,d+0x9C,114);_w8(buf,d+0x9D,111);_w8(buf,d+0x9E,99);_w8(buf,d+0x9F,101);_w8(buf,d+0xA0,115);_w8(buf,d+0xA1,115);_w8(buf,d+0xA2,72);_w8(buf,d+0xA3,101);_w8(buf,d+0xA4,97);_w8(buf,d+0xA5,112);_w8(buf,d+0xA6,0);_w8(buf,d+0xA7,0)
161 // HeapAlloc @0xA8
162 _w16(buf,d+0xA8,0);_w8(buf,d+0xAA,72);_w8(buf,d+0xAB,101);_w8(buf,d+0xAC,97);_w8(buf,d+0xAD,112);_w8(buf,d+0xAE,65);_w8(buf,d+0xAF,108);_w8(buf,d+0xB0,108);_w8(buf,d+0xB1,111);_w8(buf,d+0xB2,99);_w8(buf,d+0xB3,0)
163 // CreateFileA @0xB4
164 _w16(buf,d+0xB4,0);_w8(buf,d+0xB6,67);_w8(buf,d+0xB7,114);_w8(buf,d+0xB8,101);_w8(buf,d+0xB9,97);_w8(buf,d+0xBA,116);_w8(buf,d+0xBB,101);_w8(buf,d+0xBC,70);_w8(buf,d+0xBD,105);_w8(buf,d+0xBE,108);_w8(buf,d+0xBF,101);_w8(buf,d+0xC0,65);_w8(buf,d+0xC1,0)
165 // ReadFile @0xC2
166 _w16(buf,d+0xC2,0);_w8(buf,d+0xC4,82);_w8(buf,d+0xC5,101);_w8(buf,d+0xC6,97);_w8(buf,d+0xC7,100);_w8(buf,d+0xC8,70);_w8(buf,d+0xC9,105);_w8(buf,d+0xCA,108);_w8(buf,d+0xCB,101);_w8(buf,d+0xCC,0);_w8(buf,d+0xCD,0)
167 // "kernel32.dll" @0xCE
168 _w8(buf,d+0xCE,107);_w8(buf,d+0xCF,101);_w8(buf,d+0xD0,114);_w8(buf,d+0xD1,110);_w8(buf,d+0xD2,101);_w8(buf,d+0xD3,108);_w8(buf,d+0xD4,51);_w8(buf,d+0xD5,50);_w8(buf,d+0xD6,46);_w8(buf,d+0xD7,100);_w8(buf,d+0xD8,108);_w8(buf,d+0xD9,108);_w8(buf,d+0xDA,0)
169
170 return NX_PE_OK
171}
172
173func main() -> i64 {
174 let lenbox: *i64 = sys_mmap(16) as *i64
175 let src: *u8 = sys_read_file("/tmp/nxwin.s" as *u8, lenbox)
176 if (src as i64) == 0 { return 1 }
177 let n: i64 = lenbox[0]
178 if n <= 0 { return 2 }
179 let code: *u8 = sys_mmap(FR_CODE_CAP)
180 let off: *i64 = sys_mmap(16 * 8) as *i64
181 var z: i64 = 0
182 while z < 4 { off[z] = 0 - 1; z = z + 1 }
183 let code_len: i64 = fr_assemble(src, n, code, FR_CODE_CAP, off)
184 if code_len < 0 { return 3 }
185 if off[0] < 0 { return 4 }
186 let buf: *u8 = sys_mmap(FR_FILE_SIZE)
187 let rc: i64 = fr_emit_pe(buf, code, code_len, off)
188 if rc != NX_PE_OK { return 5 }
189 let outp: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_offc/nx_win_fread.exe" as *u8
190 if nx_pe_write_to_file(outp, buf, FR_FILE_SIZE) != NX_PE_OK { return 70 }
191 let msg: *u8 = "[substrate] nxc2-compiled native file-read PE written: nx_win_fread.exe\n" as *u8
192 sys_write(1, msg, 71)
193 return 0
194}