code wiki / (root) / nx_pe_compile_win_nishi.nx

nx_pe_compile_win_nishi.nx source

↩ module page · 714 lines · 47033 B

1// nx_pe_compile_win_nish.nx -- W-NISH: the SOVEREIGN NISHI BROWSER (nish), native Windows PE. 2// 3// Keystone-linker: takes nxc2-compiled nish (runtime/_hdl_build/nish.nx -> /tmp/nxwin.s via 4// nx_compile_x86_native) and emits a NATIVE Windows .exe whose Linux syscalls are redirected to 5// Win32 (kernel32 + ws2_32) thunks -- no WSL, no gcc, no curl/openssl/zlib. Mirrors the proven 6// nx_pe_compile_win_uiserve.nx pattern, sized for nish's ~0.8MB position-independent .text. 7// 8// STAGE 3 (live): real thunks for the whole reached syscall surface so nish performs a live HTTPS 9// fetch + render natively. WSAStartup is injected into the entry stub (nish never calls it -- it is 10// a Linux program). Stage 2a (kernel32-only, network neutralized) already proved the PE layout + 11// 1.34MB CA-bundle read + clock + console on the real nish; this stage adds the network layer. 12// 13// nish's reached syscall surface (measured from its .s, call-site counts): 14// sys_mmap x471 -> HeapAlloc; sys_write x14 -> WriteFile(fd<=2) | send(socket); 15// sys_read x7 -> stdin ReadFile(fd==0) | recv(socket); sys_close x12 -> closesocket; 16// sys_exit x4 -> ExitProcess; sys_socket x3 -> socket(honor args, TCP+UDP); 17// sys_connect x2 -> connect; sys_sendto/sys_recvfrom -> UDP DNS; sys_openat_rd x2 -> 18// CreateFileA (/dev/urandom -> fail -> deterministic entropy fallback); sys_read_file -> CA bundle; 19// sys_now_realtime_sec -> GetSystemTimeAsFileTime; sys_setsockopt x2 -> 0 (blocking sockets). 20// Everything else compiled-in but never called. 21// 22// ABI bridge: compiled nish is SysV; Win32 callees are MS-x64. The intersection of registers a SysV 23// caller assumes survive a call {rbx,rbp,rsp,r12-r15} is preserved by every Win64 callee, so the 24// thunks just remap args (rdi/rsi/rdx/rcx/r8/r9 -> rcx/rdx/r8/r9/[rsp+20]/[rsp+28]) and return in rax. 25// Image has no .reloc -> loads at preferred base 0x140000000, so absolute VAs in the url/argv blob 26// are computable; the compiled code itself is fully RIP-relative (75 leaq .L..(%rip), 0 absolute). 27// 28// lineage_id: substrate_pe_compile_win_nish_v2 (tutor-scaffold; back-fill = data-driven N-from-spec). 29 30import "nx_syscalls.nx" 31import "nxasm_x86.nx" 32import "nx_pe_writer.nx" 33 34const NSH_CODE_CAP: i64 = 0x300000 // 3 MiB assembled-code ceiling 35const NSH_STUB_LEN: i64 = 40 // sub/call WSAStartup/call build_argv/mov edi/mov rsi/call main/mov ecx/call exit/int3 36const NSH_THUNK_SLACK: i64 = 0x1000 // reserved after code for thunks + url/argv blob 37const NSH_FOFF_TEXT: i64 = 0x200 38const NSH_RVA_TEXT: i64 = 0x1000 39const NSH_IDATA_FSZ: i64 = 0x400 40 41// intra-.idata layout (2 DLLs: kernel32 [10 funcs] + ws2_32 [8 funcs]) 42const NSH_DESC_K: i64 = 0x00 // kernel32 import descriptor (20) 43const NSH_DESC_W: i64 = 0x14 // ws2_32 import descriptor (20) 44const NSH_DESC_N: i64 = 0x28 // null descriptor (20) 45const NSH_INT_K: i64 = 0x3C // kernel32 INT: 11+null (96) 46const NSH_INT_W: i64 = 0x9C // ws2_32 INT: 8+null (72) 47const NSH_IAT_K: i64 = 0xE4 // kernel32 IAT: 11+null (96) 48const NSH_IAT_W: i64 = 0x144 // ws2_32 IAT: 8+null (72) 49const NSH_NAMES: i64 = 0x18C // IMAGE_IMPORT_BY_NAME entries, then dll names 50 51// kernel32 indices (iat = rva_idata + NSH_IAT_K + k*8) 52const KF_EXIT: i64 = 0 53const KF_GPH: i64 = 1 54const KF_HA: i64 = 2 55const KF_GSH: i64 = 3 56const KF_WF: i64 = 4 57const KF_RF: i64 = 5 58const KF_CFA: i64 = 6 59const KF_GFS: i64 = 7 60const KF_GST: i64 = 8 61const KF_CH: i64 = 9 62const KF_GCL: i64 = 10 // GetCommandLineA 63// ws2_32 indices (iat = rva_idata + NSH_IAT_W + j*8) 64const WF_WSA: i64 = 0 65const WF_SOCK: i64 = 1 66const WF_CONN: i64 = 2 67const WF_SEND: i64 = 3 68const WF_RECV: i64 = 4 69const WF_STO: i64 = 5 70const WF_RFROM: i64 = 6 71const WF_CLOSE: i64 = 7 72 73const NSH_IMGBASE_LO: i64 = 0x40000000 74const NSH_IMGBASE_HI: i64 = 0x1 75const NSH_IMGBASE: i64 = 5368709120 // 0x1_4000_0000 76// fd handed back by the OPENAT thunk for "/dev/urandom" (which CreateFileA can't open on Windows). A 77// sys_read on this fd is routed to the RDRAND hardware-CSPRNG fill in the READ thunk -> real TLS entropy. 78const NSH_RAND_SENTINEL: i64 = 0x52414E44 // "RAND" 79 80func _nsh_align(x: i64, a: i64) -> i64 { return ((x + a - 1) / a) * a } 81func _nsh_rva(foff: i64) -> i64 { return NSH_RVA_TEXT + (foff - NSH_FOFF_TEXT) } 82 83// emit `call qword ptr [rip+disp32]` (FF 15) at foff targeting absolute RVA iat_rva; returns foff+6 84func _nsh_ec(buf: *u8, foff: i64, iat_rva: i64) -> i64 { 85 _w8(buf, foff, 0xFF); _w8(buf, foff + 1, 0x15) 86 _w32(buf, foff + 2, iat_rva - _nsh_rva(foff + 6)) 87 return foff + 6 88} 89 90// overwrite a shim's first 5 bytes with `jmp rel32` -> thunk_rva (shim follows the entry stub) 91func _nsh_redir(buf: *u8, shim_off: i64, thunk_rva: i64) -> i64 { 92 if shim_off < 0 { return 0 } 93 let sf: i64 = NSH_FOFF_TEXT + NSH_STUB_LEN + shim_off 94 let sr: i64 = NSH_RVA_TEXT + NSH_STUB_LEN + shim_off 95 _w8(buf, sf, 0xE9) 96 _w32(buf, sf + 1, thunk_rva - (sr + 5)) 97 return 0 98} 99 100// place an IMAGE_IMPORT_BY_NAME (hint u16=0 + name + NUL), padded even; returns next foff 101func _nsh_put_name(buf: *u8, foff: i64, s: *u8) -> i64 { 102 _w16(buf, foff, 0) 103 var i: i64 = 0 104 while s[i] != (0 as u8) { buf[foff + 2 + i] = s[i]; i = i + 1 } 105 buf[foff + 2 + i] = 0 as u8 106 var nx: i64 = foff + 2 + i + 1 107 if (nx & 1) == 1 { nx = nx + 1 } 108 return nx 109} 110 111func _nsh_put_str(buf: *u8, foff: i64, s: *u8) -> i64 { 112 var i: i64 = 0 113 while s[i] != (0 as u8) { buf[foff + i] = s[i]; i = i + 1 } 114 buf[foff + i] = 0 as u8 115 return foff + i + 1 116} 117 118func nsh_lbloff(src: *u8, lo: *i64, ll: *i64, la: *i64, n: i64, nm: *u8) -> i64 { 119 var k: i64 = 0 120 while k < n { if axc_tok_is(src, lo[k], ll[k], nm) == 1 { return la[k] } k = k + 1 } 121 return 0 - 1 122} 123 124func nsh_assemble(src: *u8, n: i64, out: *u8, out_cap: i64, off: *i64) -> i64 { 125 let lo: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 126 let ll: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 127 let la: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 128 let ls: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 129 let op0: *i64 = sys_mmap(72) as *i64 // 9 slots for SIB (matches nxasm_x86) 130 let op1: *i64 = sys_mmap(72) as *i64 131 let op2: *i64 = sys_mmap(72) as *i64 // API DRIFT FIX: axc_pass gained op2 132 let scratch: *u8 = sys_mmap(64) 133 let posbox: *i64 = sys_mmap(16) as *i64 134 let nlb: *i64 = sys_mmap(16) as *i64 135 nlb[0] = 0 136 let lh: *i64 = sys_mmap(ASM_LH_SIZE * 8) as *i64 137 138 let text_size: i64 = axc_pass(src, n, out, 0, 0, lo, ll, la, ls, nlb, lh, op0, op1, op2, scratch, posbox) 139 if text_size < 0 { return text_size } 140 let nl: i64 = nlb[0] 141 var k: i64 = 0 142 while k < nl { if ls[k] == 1 { la[k] = la[k] + text_size } k = k + 1 } 143 axc_lh_build(src, lo, ll, nl, lh) 144 let total: i64 = axc_pass(src, n, out, text_size, 1, lo, ll, la, ls, nlb, lh, op0, op1, op2, scratch, posbox) 145 if total < 0 { return total } 146 if total > out_cap { return 0 - 200 } 147 148 off[0] = nsh_lbloff(src, lo, ll, la, nl, "main") 149 off[1] = nsh_lbloff(src, lo, ll, la, nl, "sys_mmap") 150 off[2] = nsh_lbloff(src, lo, ll, la, nl, "sys_write") 151 off[3] = nsh_lbloff(src, lo, ll, la, nl, "sys_exit") 152 off[4] = nsh_lbloff(src, lo, ll, la, nl, "sys_read_file") 153 off[5] = nsh_lbloff(src, lo, ll, la, nl, "sys_now_realtime_sec") 154 off[6] = nsh_lbloff(src, lo, ll, la, nl, "sys_openat_rd") 155 off[7] = nsh_lbloff(src, lo, ll, la, nl, "sys_read") 156 off[8] = nsh_lbloff(src, lo, ll, la, nl, "sys_close") 157 off[9] = nsh_lbloff(src, lo, ll, la, nl, "sys_socket") 158 off[10] = nsh_lbloff(src, lo, ll, la, nl, "sys_connect") 159 off[11] = nsh_lbloff(src, lo, ll, la, nl, "sys_sendto") 160 off[12] = nsh_lbloff(src, lo, ll, la, nl, "sys_recvfrom") 161 off[13] = nsh_lbloff(src, lo, ll, la, nl, "sys_setsockopt") 162 off[14] = nsh_lbloff(src, lo, ll, la, nl, "sys_clock_gettime_real") 163 off[15] = nsh_lbloff(src, lo, ll, la, nl, "sys_clock_gettime_mono") 164 return total 165} 166 167func nsh_emit_pe(buf: *u8, code: *u8, code_len: i64, off: *i64, 168 file_size: i64, text_fsz: i64, rva_idata: i64) -> i64 { 169 if (buf as i64) == 0 { return 0 - NX_PE_BAD_INPUT } 170 if off[0] < 0 { return 0 - NX_PE_BAD_INPUT } 171 172 let foff_idata: i64 = NSH_FOFF_TEXT + text_fsz 173 let size_of_image: i64 = rva_idata + 0x1000 174 175 // IAT slot RVAs 176 let iat_exit: i64 = rva_idata + NSH_IAT_K + KF_EXIT * 8 177 let iat_gph: i64 = rva_idata + NSH_IAT_K + KF_GPH * 8 178 let iat_ha: i64 = rva_idata + NSH_IAT_K + KF_HA * 8 179 let iat_gsh: i64 = rva_idata + NSH_IAT_K + KF_GSH * 8 180 let iat_wf: i64 = rva_idata + NSH_IAT_K + KF_WF * 8 181 let iat_rf: i64 = rva_idata + NSH_IAT_K + KF_RF * 8 182 let iat_cfa: i64 = rva_idata + NSH_IAT_K + KF_CFA * 8 183 let iat_gfs: i64 = rva_idata + NSH_IAT_K + KF_GFS * 8 184 let iat_gst: i64 = rva_idata + NSH_IAT_K + KF_GST * 8 185 let iat_ch: i64 = rva_idata + NSH_IAT_K + KF_CH * 8 186 let iat_gcl: i64 = rva_idata + NSH_IAT_K + KF_GCL * 8 187 let wiat_wsa: i64 = rva_idata + NSH_IAT_W + WF_WSA * 8 188 let wiat_sock: i64 = rva_idata + NSH_IAT_W + WF_SOCK * 8 189 let wiat_conn: i64 = rva_idata + NSH_IAT_W + WF_CONN * 8 190 let wiat_send: i64 = rva_idata + NSH_IAT_W + WF_SEND * 8 191 let wiat_recv: i64 = rva_idata + NSH_IAT_W + WF_RECV * 8 192 let wiat_sto: i64 = rva_idata + NSH_IAT_W + WF_STO * 8 193 let wiat_rfrom: i64 = rva_idata + NSH_IAT_W + WF_RFROM * 8 194 let wiat_close: i64 = rva_idata + NSH_IAT_W + WF_CLOSE * 8 195 196 // ===== headers ===== 197 _w16(buf, 0, 0x5A4D); _w32(buf, 0x3C, FOFF_PE_SIG); _w32(buf, FOFF_PE_SIG, 0x00004550) 198 _w16(buf, FOFF_COFF + 0, PE_MACHINE_AMD64); _w16(buf, FOFF_COFF + 2, 2) 199 _w16(buf, FOFF_COFF + 16, 0xF0); _w16(buf, FOFF_COFF + 18, PE_CHAR_EXEC | PE_CHAR_LARGE_ADDR) 200 _w16(buf, FOFF_OPT + 0, PE_OH_MAGIC_PEPLUS); _w8(buf, FOFF_OPT + 2, 1) 201 _w32(buf, FOFF_OPT + 4, text_fsz); _w32(buf, FOFF_OPT + 8, NSH_IDATA_FSZ) 202 _w32(buf, FOFF_OPT + 16, NSH_RVA_TEXT); _w32(buf, FOFF_OPT + 20, NSH_RVA_TEXT) 203 _w64(buf, FOFF_OPT + 24, NSH_IMGBASE_LO, NSH_IMGBASE_HI) 204 _w32(buf, FOFF_OPT + 32, 0x1000); _w32(buf, FOFF_OPT + 36, 0x200) 205 _w16(buf, FOFF_OPT + 40, 6); _w16(buf, FOFF_OPT + 48, 6) 206 _w32(buf, FOFF_OPT + 56, size_of_image); _w32(buf, FOFF_OPT + 60, 0x200) 207 _w16(buf, FOFF_OPT + 68, PE_SUBSYSTEM_CONSOLE) 208 _w64(buf, FOFF_OPT + 72, 0x100000, 0); _w64(buf, FOFF_OPT + 80, 0x1000, 0) 209 _w64(buf, FOFF_OPT + 88, 0x100000, 0); _w64(buf, FOFF_OPT + 96, 0x1000, 0) 210 _w32(buf, FOFF_OPT + 108, 16) 211 _w32(buf, FOFF_OPT + 112 + 8, rva_idata); _w32(buf, FOFF_OPT + 112 + 12, 0x3C) 212 213 // .text is CODE|EXECUTE|READ|WRITE (0xE0000020): the blob holds nish's WRITABLE statics (scratch- 214 // arena state NX_SCRATCH_NBLOCKS/cursor/block-ptrs, rand_fd_slot) inline -- on Linux these live in 215 // a writable .bss, but here code+data share one section, so it MUST be writable or the crypto's first 216 // static write (e.g. NX_SCRATCH_NBLOCKS=1) faults (0xC0000005). [refine later: split a .data section] 217 _emit_section_header(buf, FOFF_SECT_TBL, 46, 116, 101, 120, 116, 0, 0, 0, text_fsz, NSH_RVA_TEXT, text_fsz, NSH_FOFF_TEXT, 0xE0000020) 218 _emit_section_header(buf, FOFF_SECT_TBL + 40, 46, 105, 100, 97, 116, 97, 0, 0, 0x380, rva_idata, NSH_IDATA_FSZ, foff_idata, PE_SECT_DATA_R) 219 220 // ===== copy compiled nish code after the entry stub ===== 221 var i: i64 = 0 222 while i < code_len { buf[NSH_FOFF_TEXT + NSH_STUB_LEN + i] = code[i]; i = i + 1 } 223 224 // ===== writable argv array (build_argv fills it from GetCommandLineA at runtime). Placed FIRST, 225 // before the thunks, so its RVA is known to build_argv + the entry stub. 8 slots, zeroed. ===== 226 var a: i64 = NSH_FOFF_TEXT + NSH_STUB_LEN + code_len 227 let r_argv: i64 = _nsh_rva(a) 228 var zq: i64 = 0 229 while zq < 64 { buf[a + zq] = 0 as u8; zq = zq + 1 } 230 a = a + 64 231 232 // HALLOC: sys_mmap(size=rdi) -> HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size). rdi is 233 // Win64-nonvolatile. HEAP_ZERO_MEMORY (0x8) is REQUIRED: nish was written for Linux mmap, which 234 // returns zero-filled pages; bare HeapAlloc returns uninitialized memory -> garbage in zero-assumed 235 // struct/buffer fields -> access violation in the TLS path. 236 let r_halloc: i64 = _nsh_rva(a) 237 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28); a = a + 4 238 a = _nsh_ec(buf, a, iat_gph) 239 _w8(buf,a+0,0x48);_w8(buf,a+1,0x89);_w8(buf,a+2,0xC1) // mov rcx,rax 240 _w8(buf,a+3,0xBA);_w32(buf,a+4,8) // mov edx,8 (HEAP_ZERO_MEMORY) 241 _w8(buf,a+8,0x49);_w8(buf,a+9,0x89);_w8(buf,a+10,0xF8); a = a + 11 // mov r8,rdi 242 a = _nsh_ec(buf, a, iat_ha) 243 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x28);_w8(buf,a+4,0xC3); a = a + 5 244 245 // WRITE: sys_write(fd=rdi,buf=rsi,n=rdx) -> fd<=2 ? WriteFile : send 246 let r_write: i64 = _nsh_rva(a) 247 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xFF);_w8(buf,a+3,0x02) // cmp rdi,2 248 _w8(buf,a+4,0x7F) // jg L_SEND (patched) 249 let wjg: i64 = a + 5 250 a = a + 6 251 let wcs: i64 = a 252 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x38) // sub rsp,0x38 253 _w8(buf,a+4,0x48);_w8(buf,a+5,0x89);_w8(buf,a+6,0x74);_w8(buf,a+7,0x24);_w8(buf,a+8,0x28) 254 _w8(buf,a+9,0x48);_w8(buf,a+10,0x89);_w8(buf,a+11,0x54);_w8(buf,a+12,0x24);_w8(buf,a+13,0x30) 255 _w8(buf,a+14,0xB9);_w8(buf,a+15,0xF5);_w8(buf,a+16,0xFF);_w8(buf,a+17,0xFF);_w8(buf,a+18,0xFF) // mov ecx,-11 256 _w8(buf,a+19,0x83);_w8(buf,a+20,0xFF);_w8(buf,a+21,0x02) // cmp edi,2 257 _w8(buf,a+22,0x75);_w8(buf,a+23,0x05) // jne +5 258 _w8(buf,a+24,0xB9);_w8(buf,a+25,0xF4);_w8(buf,a+26,0xFF);_w8(buf,a+27,0xFF);_w8(buf,a+28,0xFF) // mov ecx,-12 259 a = a + 29 260 a = _nsh_ec(buf, a, iat_gsh) 261 _w8(buf,a+0,0x48);_w8(buf,a+1,0x89);_w8(buf,a+2,0xC1) 262 _w8(buf,a+3,0x48);_w8(buf,a+4,0x8B);_w8(buf,a+5,0x54);_w8(buf,a+6,0x24);_w8(buf,a+7,0x28) 263 _w8(buf,a+8,0x4C);_w8(buf,a+9,0x8B);_w8(buf,a+10,0x44);_w8(buf,a+11,0x24);_w8(buf,a+12,0x30) 264 _w8(buf,a+13,0x4C);_w8(buf,a+14,0x8D);_w8(buf,a+15,0x4C);_w8(buf,a+16,0x24);_w8(buf,a+17,0x28) 265 _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) 266 a = a + 27 267 a = _nsh_ec(buf, a, iat_wf) 268 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x38);_w8(buf,a+4,0xC3); a = a + 5 269 _w8(buf, wjg, a - wcs) // patch jg rel8 270 // L_SEND: send(fd,buf,n,0) 271 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28) 272 _w8(buf,a+4,0x49);_w8(buf,a+5,0x89);_w8(buf,a+6,0xD0) // mov r8,rdx 273 _w8(buf,a+7,0x48);_w8(buf,a+8,0x89);_w8(buf,a+9,0xF2) // mov rdx,rsi 274 _w8(buf,a+10,0x48);_w8(buf,a+11,0x89);_w8(buf,a+12,0xF9) // mov rcx,rdi 275 _w8(buf,a+13,0x45);_w8(buf,a+14,0x31);_w8(buf,a+15,0xC9) // xor r9d,r9d 276 a = a + 16 277 a = _nsh_ec(buf, a, wiat_send) 278 _w8(buf,a+0,0x48);_w8(buf,a+1,0x98); a = a + 2 // cdqe: int->i64 279 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x28);_w8(buf,a+4,0xC3); a = a + 5 280 281 // URAND: sys_read(fd==NSH_RAND_SENTINEL) -> fill rsi[0..rdx) with hardware entropy, return rdx. 282 // CPUID-GUARDED so it never #UD-faults: leaf-1 ECX bit 30 = RDRAND support. Present -> on-die RDRAND 283 // (NIST SP800-90 hw CSPRNG; TLS client_random + ephemeral x25519/ECDHE keys UNPREDICTABLE). ABSENT 284 // (pre-2012 CPU) -> RDTSC-seeded fallback = GRACEFUL DEGRADATION (weak but non-constant, no crash) 285 // instead of an illegal-instruction fault. Replaces nishi's old deterministic 0xC0../0xA0.. fixed-key 286 // fallback (predictable keys = MITM-able). rbx is pushed (cpuid clobbers it); bl carries the support flag. 287 let r_urand: i64 = _nsh_rva(a) 288 _w8(buf,a+0,0x53) // push rbx 289 _w8(buf,a+1,0x49);_w8(buf,a+2,0x89);_w8(buf,a+3,0xF1) // mov r9,rsi (dst ptr) 290 _w8(buf,a+4,0x49);_w8(buf,a+5,0x89);_w8(buf,a+6,0xD0) // mov r8,rdx (count) 291 _w8(buf,a+7,0xB8);_w32(buf,a+8,1) // mov eax,1 292 _w8(buf,a+12,0x0F);_w8(buf,a+13,0xA2) // cpuid (clobbers eax/ebx/ecx/edx) 293 _w8(buf,a+14,0x0F);_w8(buf,a+15,0xBA);_w8(buf,a+16,0xE1);_w8(buf,a+17,0x1E) // bt ecx,30 (RDRAND bit) 294 _w8(buf,a+18,0x0F);_w8(buf,a+19,0x92);_w8(buf,a+20,0xC3) // setc bl (bl = RDRAND supported) 295 _w8(buf,a+21,0x4D);_w8(buf,a+22,0x85);_w8(buf,a+23,0xC0) // L_LOOP: test r8,r8 296 _w8(buf,a+24,0x74);_w8(buf,a+25,0x20) // jz L_DONE (+0x20) 297 _w8(buf,a+26,0x84);_w8(buf,a+27,0xDB) // test bl,bl 298 _w8(buf,a+28,0x74);_w8(buf,a+29,0x0F) // jz L_TSC (no RDRAND -> fallback) 299 _w8(buf,a+30,0xB9);_w32(buf,a+31,16) // mov ecx,16 (RDRAND retry budget) 300 _w8(buf,a+35,0x48);_w8(buf,a+36,0x0F);_w8(buf,a+37,0xC7);_w8(buf,a+38,0xF0) // L_RETRY: rdrand rax 301 _w8(buf,a+39,0x72);_w8(buf,a+40,0x06) // jc L_HAVE (CF=1 -> got entropy) 302 _w8(buf,a+41,0xFF);_w8(buf,a+42,0xC9) // dec ecx 303 _w8(buf,a+43,0x75);_w8(buf,a+44,0xF6) // jnz L_RETRY (-10; exhausted -> L_TSC) 304 _w8(buf,a+45,0x0F);_w8(buf,a+46,0x31) // L_TSC: rdtsc (eax = low TSC) 305 _w8(buf,a+47,0x41);_w8(buf,a+48,0x88);_w8(buf,a+49,0x01) // L_HAVE: mov [r9],al 306 _w8(buf,a+50,0x49);_w8(buf,a+51,0xFF);_w8(buf,a+52,0xC1) // inc r9 307 _w8(buf,a+53,0x49);_w8(buf,a+54,0xFF);_w8(buf,a+55,0xC8) // dec r8 308 _w8(buf,a+56,0xEB);_w8(buf,a+57,0xDB) // jmp L_LOOP (-37) 309 _w8(buf,a+58,0x48);_w8(buf,a+59,0x89);_w8(buf,a+60,0xD0) // L_DONE: mov rax,rdx (return n) 310 _w8(buf,a+61,0x5B) // pop rbx 311 _w8(buf,a+62,0xC3); a = a + 63 // ret 312 313 // READ: sys_read(fd=rdi,buf=rsi,n=rdx) -> fd==SENTINEL ? rdrand-fill : fd==0 ? stdin : (fd<3 ? -1 : recv) 314 let r_read: i64 = _nsh_rva(a) 315 _w8(buf,a+0,0x48);_w8(buf,a+1,0x81);_w8(buf,a+2,0xFF);_w32(buf,a+3,NSH_RAND_SENTINEL) // cmp rdi,sentinel 316 _w8(buf,a+7,0x0F);_w8(buf,a+8,0x84);_w32(buf,a+9, r_urand - _nsh_rva(a+13)) // je r_urand 317 a = a + 13 318 _w8(buf,a+0,0x48);_w8(buf,a+1,0x85);_w8(buf,a+2,0xFF) // test rdi,rdi 319 _w8(buf,a+3,0x75) // jnz L_NOTSTDIN (patched) 320 let rjn: i64 = a + 4 321 a = a + 5 322 let rsd: i64 = a 323 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x38) // sub rsp,0x38 324 _w8(buf,a+4,0x48);_w8(buf,a+5,0x89);_w8(buf,a+6,0x74);_w8(buf,a+7,0x24);_w8(buf,a+8,0x28) 325 _w8(buf,a+9,0x48);_w8(buf,a+10,0x89);_w8(buf,a+11,0x54);_w8(buf,a+12,0x24);_w8(buf,a+13,0x30) 326 _w8(buf,a+14,0xB9);_w8(buf,a+15,0xF6);_w8(buf,a+16,0xFF);_w8(buf,a+17,0xFF);_w8(buf,a+18,0xFF) // mov ecx,-10 327 a = a + 19 328 a = _nsh_ec(buf, a, iat_gsh) 329 _w8(buf,a+0,0x48);_w8(buf,a+1,0x89);_w8(buf,a+2,0xC1) 330 _w8(buf,a+3,0x48);_w8(buf,a+4,0x8B);_w8(buf,a+5,0x54);_w8(buf,a+6,0x24);_w8(buf,a+7,0x28) 331 _w8(buf,a+8,0x4C);_w8(buf,a+9,0x8B);_w8(buf,a+10,0x44);_w8(buf,a+11,0x24);_w8(buf,a+12,0x30) 332 _w8(buf,a+13,0x4C);_w8(buf,a+14,0x8D);_w8(buf,a+15,0x4C);_w8(buf,a+16,0x24);_w8(buf,a+17,0x28) 333 _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) 334 a = a + 27 335 a = _nsh_ec(buf, a, iat_rf) 336 _w8(buf,a+0,0x8B);_w8(buf,a+1,0x44);_w8(buf,a+2,0x24);_w8(buf,a+3,0x28) // mov eax,[rsp+0x28] (got) 337 _w8(buf,a+4,0x48);_w8(buf,a+5,0x83);_w8(buf,a+6,0xC4);_w8(buf,a+7,0x38);_w8(buf,a+8,0xC3); a = a + 9 338 _w8(buf, rjn, a - rsd) // patch jnz rel8 339 // L_NOTSTDIN: fd<3 -> -1 340 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xFF);_w8(buf,a+3,0x02) // cmp rdi,2 341 _w8(buf,a+4,0x7F) // jg L_RECV (patched) 342 let rjg: i64 = a + 5 343 a = a + 6 344 let rf12: i64 = a 345 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC8);_w8(buf,a+3,0xFF);_w8(buf,a+4,0xC3); a = a + 5 // or rax,-1; ret 346 _w8(buf, rjg, a - rf12) // patch jg rel8 347 // L_RECV: recv(fd,buf,n,0) 348 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28) 349 _w8(buf,a+4,0x49);_w8(buf,a+5,0x89);_w8(buf,a+6,0xD0) 350 _w8(buf,a+7,0x48);_w8(buf,a+8,0x89);_w8(buf,a+9,0xF2) 351 _w8(buf,a+10,0x48);_w8(buf,a+11,0x89);_w8(buf,a+12,0xF9) 352 _w8(buf,a+13,0x45);_w8(buf,a+14,0x31);_w8(buf,a+15,0xC9) 353 a = a + 16 354 a = _nsh_ec(buf, a, wiat_recv) 355 _w8(buf,a+0,0x48);_w8(buf,a+1,0x98); a = a + 2 // cdqe: int->i64 356 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x28);_w8(buf,a+4,0xC3); a = a + 5 357 358 // CLOSE: sys_close(fd=rdi) -> closesocket 359 let r_close: i64 = _nsh_rva(a) 360 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28) 361 _w8(buf,a+4,0x48);_w8(buf,a+5,0x89);_w8(buf,a+6,0xF9); a = a + 7 362 a = _nsh_ec(buf, a, wiat_close) 363 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x28);_w8(buf,a+4,0xC3); a = a + 5 364 365 // EXIT: sys_exit(code=rdi) -> ExitProcess 366 let r_exit: i64 = _nsh_rva(a) 367 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28) 368 _w8(buf,a+4,0x89);_w8(buf,a+5,0xF9); a = a + 6 369 a = _nsh_ec(buf, a, iat_exit) 370 _w8(buf,a+0,0xCC); a = a + 1 371 372 // NOWSEC: sys_now_realtime_sec() -> GetSystemTimeAsFileTime -> unix seconds 373 let r_nowsec: i64 = _nsh_rva(a) 374 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28) 375 _w8(buf,a+4,0x48);_w8(buf,a+5,0x8D);_w8(buf,a+6,0x4C);_w8(buf,a+7,0x24);_w8(buf,a+8,0x20) 376 a = a + 9 377 a = _nsh_ec(buf, a, iat_gst) 378 _w8(buf,a+0,0x48);_w8(buf,a+1,0x8B);_w8(buf,a+2,0x44);_w8(buf,a+3,0x24);_w8(buf,a+4,0x20) 379 _w8(buf,a+5,0x31);_w8(buf,a+6,0xD2) 380 _w8(buf,a+7,0x48);_w8(buf,a+8,0xC7);_w8(buf,a+9,0xC1);_w32(buf,a+10,10000000) 381 _w8(buf,a+14,0x48);_w8(buf,a+15,0xF7);_w8(buf,a+16,0xF1) 382 _w8(buf,a+17,0x48);_w8(buf,a+18,0xB9);_w32(buf,a+19,3054539008);_w32(buf,a+23,2) 383 _w8(buf,a+27,0x48);_w8(buf,a+28,0x29);_w8(buf,a+29,0xC8) 384 _w8(buf,a+30,0x48);_w8(buf,a+31,0x83);_w8(buf,a+32,0xC4);_w8(buf,a+33,0x28);_w8(buf,a+34,0xC3); a = a + 35 385 386 // MONO: sys_clock_gettime_mono(ts=rdi) -> GetSystemTimeAsFileTime -> fill ts[0]=sec ts[1]=nsec 387 // (native ms/us clock for sovereign perf timing; reuses the GetSystemTimeAsFileTime import). 388 let r_mono: i64 = _nsh_rva(a) 389 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28) // sub rsp,0x28 390 _w8(buf,a+4,0x48);_w8(buf,a+5,0x8D);_w8(buf,a+6,0x4C);_w8(buf,a+7,0x24);_w8(buf,a+8,0x20) // lea rcx,[rsp+0x20] 391 a = a + 9 392 a = _nsh_ec(buf, a, iat_gst) // call [GetSystemTimeAsFileTime] 393 _w8(buf,a+0,0x48);_w8(buf,a+1,0x8B);_w8(buf,a+2,0x44);_w8(buf,a+3,0x24);_w8(buf,a+4,0x20) // mov rax,[rsp+0x20] 394 _w8(buf,a+5,0x31);_w8(buf,a+6,0xD2) // xor edx,edx 395 _w8(buf,a+7,0x48);_w8(buf,a+8,0xC7);_w8(buf,a+9,0xC1);_w32(buf,a+10,10000000) // mov rcx,10000000 396 _w8(buf,a+14,0x48);_w8(buf,a+15,0xF7);_w8(buf,a+16,0xF1) // div rcx -> rax=sec rdx=rem 397 _w8(buf,a+17,0x48);_w8(buf,a+18,0x89);_w8(buf,a+19,0x07) // mov [rdi],rax 398 _w8(buf,a+20,0x48);_w8(buf,a+21,0x89);_w8(buf,a+22,0xD0) // mov rax,rdx 399 _w8(buf,a+23,0x48);_w8(buf,a+24,0xC7);_w8(buf,a+25,0xC1);_w32(buf,a+26,100) // mov rcx,100 400 _w8(buf,a+30,0x48);_w8(buf,a+31,0xF7);_w8(buf,a+32,0xE9) // imul rcx -> rax=nsec 401 _w8(buf,a+33,0x48);_w8(buf,a+34,0x89);_w8(buf,a+35,0x47);_w8(buf,a+36,0x08) // mov [rdi+8],rax 402 _w8(buf,a+37,0x31);_w8(buf,a+38,0xC0) // xor eax,eax 403 _w8(buf,a+39,0x48);_w8(buf,a+40,0x83);_w8(buf,a+41,0xC4);_w8(buf,a+42,0x28) // add rsp,0x28 404 _w8(buf,a+43,0xC3); a = a + 44 // ret 405 406 // OPENAT: sys_openat_rd(path=rdi) -> CreateFileA(...) -> handle or -1 407 let r_openat: i64 = _nsh_rva(a) 408 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x48) 409 _w8(buf,a+4,0x48);_w8(buf,a+5,0x89);_w8(buf,a+6,0xF9) 410 _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) 411 _w8(buf,a+12,0x41);_w8(buf,a+13,0xB8);_w32(buf,a+14,1) 412 _w8(buf,a+18,0x45);_w8(buf,a+19,0x31);_w8(buf,a+20,0xC9) 413 _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) 414 _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) 415 _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) 416 a = a + 46 417 a = _nsh_ec(buf, a, iat_cfa) 418 // /dev/urandom (and any path Windows can't open) -> CreateFileA returns -1; hand back the RAND 419 // SENTINEL fd instead, so nishi's `ufd >= 0` urandom branch runs and sys_read rdrand-fills it 420 // (was: -1 -> nishi's DETERMINISTIC fixed-key fallback = the MITM-able hole this closes). 421 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xF8);_w8(buf,a+3,0xFF) // cmp rax,-1 422 _w8(buf,a+4,0x75);_w8(buf,a+5,0x05) // jne +5 (real handle -> keep) 423 _w8(buf,a+6,0xB8);_w32(buf,a+7,NSH_RAND_SENTINEL); a = a + 11 // mov eax,sentinel 424 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x48);_w8(buf,a+4,0xC3); a = a + 5 425 426 // READFILE: sys_read_file(path=rdi, out_len=rsi) -> buf 427 let r_readfile: i64 = _nsh_rva(a) 428 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x58) 429 _w8(buf,a+4,0x48);_w8(buf,a+5,0x89);_w8(buf,a+6,0x74);_w8(buf,a+7,0x24);_w8(buf,a+8,0x48) 430 _w8(buf,a+9,0x48);_w8(buf,a+10,0x89);_w8(buf,a+11,0xF9) 431 _w8(buf,a+12,0xBA);_w8(buf,a+13,0x00);_w8(buf,a+14,0x00);_w8(buf,a+15,0x00);_w8(buf,a+16,0x80) 432 _w8(buf,a+17,0x41);_w8(buf,a+18,0xB8);_w32(buf,a+19,1) 433 _w8(buf,a+23,0x45);_w8(buf,a+24,0x31);_w8(buf,a+25,0xC9) 434 _w8(buf,a+26,0xC7);_w8(buf,a+27,0x44);_w8(buf,a+28,0x24);_w8(buf,a+29,0x20);_w32(buf,a+30,3) 435 _w8(buf,a+34,0xC7);_w8(buf,a+35,0x44);_w8(buf,a+36,0x24);_w8(buf,a+37,0x28);_w32(buf,a+38,0x80) 436 _w8(buf,a+42,0x48);_w8(buf,a+43,0xC7);_w8(buf,a+44,0x44);_w8(buf,a+45,0x24);_w8(buf,a+46,0x30);_w32(buf,a+47,0) 437 a = a + 51 438 a = _nsh_ec(buf, a, iat_cfa) 439 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xF8);_w8(buf,a+3,0xFF) // cmp rax,-1 440 _w8(buf,a+4,0x75);_w8(buf,a+5,0x13) // jne +0x13 441 _w8(buf,a+6,0x48);_w8(buf,a+7,0x8B);_w8(buf,a+8,0x44);_w8(buf,a+9,0x24);_w8(buf,a+10,0x48) 442 _w8(buf,a+11,0x48);_w8(buf,a+12,0xC7);_w8(buf,a+13,0x00);_w32(buf,a+14,0) 443 _w8(buf,a+18,0x31);_w8(buf,a+19,0xC0) 444 _w8(buf,a+20,0x48);_w8(buf,a+21,0x83);_w8(buf,a+22,0xC4);_w8(buf,a+23,0x58);_w8(buf,a+24,0xC3) 445 a = a + 25 446 _w8(buf,a+0,0x48);_w8(buf,a+1,0x89);_w8(buf,a+2,0x44);_w8(buf,a+3,0x24);_w8(buf,a+4,0x40) 447 _w8(buf,a+5,0x48);_w8(buf,a+6,0x89);_w8(buf,a+7,0xC1) 448 _w8(buf,a+8,0x48);_w8(buf,a+9,0x8D);_w8(buf,a+10,0x54);_w8(buf,a+11,0x24);_w8(buf,a+12,0x50) 449 a = a + 13 450 a = _nsh_ec(buf, a, iat_gfs) 451 a = _nsh_ec(buf, a, iat_gph) 452 _w8(buf,a+0,0x48);_w8(buf,a+1,0x89);_w8(buf,a+2,0xC1) 453 _w8(buf,a+3,0x31);_w8(buf,a+4,0xD2) 454 _w8(buf,a+5,0x4C);_w8(buf,a+6,0x8B);_w8(buf,a+7,0x44);_w8(buf,a+8,0x24);_w8(buf,a+9,0x50) 455 _w8(buf,a+10,0x49);_w8(buf,a+11,0x83);_w8(buf,a+12,0xC0);_w8(buf,a+13,0x10) 456 a = a + 14 457 a = _nsh_ec(buf, a, iat_ha) 458 _w8(buf,a+0,0x48);_w8(buf,a+1,0x89);_w8(buf,a+2,0x44);_w8(buf,a+3,0x24);_w8(buf,a+4,0x38) 459 _w8(buf,a+5,0x48);_w8(buf,a+6,0x8B);_w8(buf,a+7,0x4C);_w8(buf,a+8,0x24);_w8(buf,a+9,0x40) 460 _w8(buf,a+10,0x48);_w8(buf,a+11,0x89);_w8(buf,a+12,0xC2) 461 _w8(buf,a+13,0x4C);_w8(buf,a+14,0x8B);_w8(buf,a+15,0x44);_w8(buf,a+16,0x24);_w8(buf,a+17,0x50) 462 _w8(buf,a+18,0x4C);_w8(buf,a+19,0x8D);_w8(buf,a+20,0x4C);_w8(buf,a+21,0x24);_w8(buf,a+22,0x28) 463 _w8(buf,a+23,0x48);_w8(buf,a+24,0xC7);_w8(buf,a+25,0x44);_w8(buf,a+26,0x24);_w8(buf,a+27,0x20);_w32(buf,a+28,0) 464 a = a + 32 465 a = _nsh_ec(buf, a, iat_rf) 466 _w8(buf,a+0,0x48);_w8(buf,a+1,0x8B);_w8(buf,a+2,0x4C);_w8(buf,a+3,0x24);_w8(buf,a+4,0x40) 467 a = a + 5 468 a = _nsh_ec(buf, a, iat_ch) 469 _w8(buf,a+0,0x48);_w8(buf,a+1,0x8B);_w8(buf,a+2,0x44);_w8(buf,a+3,0x24);_w8(buf,a+4,0x48) 470 _w8(buf,a+5,0x48);_w8(buf,a+6,0x8B);_w8(buf,a+7,0x54);_w8(buf,a+8,0x24);_w8(buf,a+9,0x50) 471 _w8(buf,a+10,0x48);_w8(buf,a+11,0x89);_w8(buf,a+12,0x10) 472 _w8(buf,a+13,0x48);_w8(buf,a+14,0x8B);_w8(buf,a+15,0x44);_w8(buf,a+16,0x24);_w8(buf,a+17,0x38) 473 _w8(buf,a+18,0x48);_w8(buf,a+19,0x8B);_w8(buf,a+20,0x4C);_w8(buf,a+21,0x24);_w8(buf,a+22,0x50) 474 _w8(buf,a+23,0xC6);_w8(buf,a+24,0x04);_w8(buf,a+25,0x08);_w8(buf,a+26,0x00) 475 _w8(buf,a+27,0x48);_w8(buf,a+28,0x8B);_w8(buf,a+29,0x44);_w8(buf,a+30,0x24);_w8(buf,a+31,0x38) 476 _w8(buf,a+32,0x48);_w8(buf,a+33,0x83);_w8(buf,a+34,0xC4);_w8(buf,a+35,0x58);_w8(buf,a+36,0xC3) 477 a = a + 37 478 479 // WSAINIT: WSAStartup(0x0202, &wsadata) -- called from entry stub 480 let r_wsa: i64 = _nsh_rva(a) 481 _w8(buf,a+0,0x48);_w8(buf,a+1,0x81);_w8(buf,a+2,0xEC);_w32(buf,a+3,0x228) 482 _w8(buf,a+7,0xB9);_w32(buf,a+8,0x0202) 483 _w8(buf,a+12,0x48);_w8(buf,a+13,0x8D);_w8(buf,a+14,0x54);_w8(buf,a+15,0x24);_w8(buf,a+16,0x28) 484 a = a + 17 485 a = _nsh_ec(buf, a, wiat_wsa) 486 _w8(buf,a+0,0x48);_w8(buf,a+1,0x81);_w8(buf,a+2,0xC4);_w32(buf,a+3,0x228);_w8(buf,a+7,0xC3); a = a + 8 487 488 // SOCKET: sys_socket(domain=rdi,type=rsi,proto=rdx) -> socket(af,type,proto) 489 let r_socket: i64 = _nsh_rva(a) 490 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28) 491 _w8(buf,a+4,0x49);_w8(buf,a+5,0x89);_w8(buf,a+6,0xD0) // mov r8,rdx 492 _w8(buf,a+7,0x48);_w8(buf,a+8,0x89);_w8(buf,a+9,0xF2) // mov rdx,rsi 493 _w8(buf,a+10,0x48);_w8(buf,a+11,0x89);_w8(buf,a+12,0xF9) // mov rcx,rdi 494 a = a + 13 495 a = _nsh_ec(buf, a, wiat_sock) 496 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x28);_w8(buf,a+4,0xC3); a = a + 5 497 498 // CONNECT: sys_connect(fd=rdi,addr=rsi,addrlen=rdx) -> connect(s,name,namelen) 499 let r_connect: i64 = _nsh_rva(a) 500 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28) 501 _w8(buf,a+4,0x49);_w8(buf,a+5,0x89);_w8(buf,a+6,0xD0) 502 _w8(buf,a+7,0x48);_w8(buf,a+8,0x89);_w8(buf,a+9,0xF2) 503 _w8(buf,a+10,0x48);_w8(buf,a+11,0x89);_w8(buf,a+12,0xF9) 504 a = a + 13 505 a = _nsh_ec(buf, a, wiat_conn) 506 _w8(buf,a+0,0x48);_w8(buf,a+1,0x98); a = a + 2 // cdqe: int->i64 507 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x28);_w8(buf,a+4,0xC3); a = a + 5 508 509 // SENDTO: sys_sendto(fd,buf,n,flags,addr,addrlen) -> sendto(s,buf,len,flags,to,tolen) 510 let r_sendto: i64 = _nsh_rva(a) 511 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x38) 512 _w8(buf,a+4,0x4C);_w8(buf,a+5,0x89);_w8(buf,a+6,0x4C);_w8(buf,a+7,0x24);_w8(buf,a+8,0x28) // mov [rsp+0x28],r9 (tolen) 513 _w8(buf,a+9,0x4C);_w8(buf,a+10,0x89);_w8(buf,a+11,0x44);_w8(buf,a+12,0x24);_w8(buf,a+13,0x20) // mov [rsp+0x20],r8 (to) 514 _w8(buf,a+14,0x49);_w8(buf,a+15,0x89);_w8(buf,a+16,0xC9) // mov r9,rcx (flags) 515 _w8(buf,a+17,0x49);_w8(buf,a+18,0x89);_w8(buf,a+19,0xD0) // mov r8,rdx (len) 516 _w8(buf,a+20,0x48);_w8(buf,a+21,0x89);_w8(buf,a+22,0xF2) // mov rdx,rsi (buf) 517 _w8(buf,a+23,0x48);_w8(buf,a+24,0x89);_w8(buf,a+25,0xF9) // mov rcx,rdi (s) 518 a = a + 26 519 a = _nsh_ec(buf, a, wiat_sto) 520 _w8(buf,a+0,0x48);_w8(buf,a+1,0x98); a = a + 2 // cdqe: int->i64 521 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x38);_w8(buf,a+4,0xC3); a = a + 5 522 523 // RECVFROM: sys_recvfrom(fd,buf,n,flags,addr,addrlen) -> recvfrom(s,buf,len,flags,from,fromlen) 524 let r_recvfrom: i64 = _nsh_rva(a) 525 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x38) 526 _w8(buf,a+4,0x4C);_w8(buf,a+5,0x89);_w8(buf,a+6,0x4C);_w8(buf,a+7,0x24);_w8(buf,a+8,0x28) 527 _w8(buf,a+9,0x4C);_w8(buf,a+10,0x89);_w8(buf,a+11,0x44);_w8(buf,a+12,0x24);_w8(buf,a+13,0x20) 528 _w8(buf,a+14,0x49);_w8(buf,a+15,0x89);_w8(buf,a+16,0xC9) 529 _w8(buf,a+17,0x49);_w8(buf,a+18,0x89);_w8(buf,a+19,0xD0) 530 _w8(buf,a+20,0x48);_w8(buf,a+21,0x89);_w8(buf,a+22,0xF2) 531 _w8(buf,a+23,0x48);_w8(buf,a+24,0x89);_w8(buf,a+25,0xF9) 532 a = a + 26 533 a = _nsh_ec(buf, a, wiat_rfrom) 534 _w8(buf,a+0,0x48);_w8(buf,a+1,0x98); a = a + 2 // cdqe: int->i64 535 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xC4);_w8(buf,a+3,0x38);_w8(buf,a+4,0xC3); a = a + 5 536 537 // ZERO stub: xor eax,eax; ret (sys_setsockopt -> 0; unreached clock helpers -> 0) 538 let r_zero: i64 = _nsh_rva(a) 539 _w8(buf,a+0,0x31);_w8(buf,a+1,0xC0);_w8(buf,a+2,0xC3); a = a + 3 540 541 // build_argv: GetCommandLineA() -> tokenize into ARGV_ARR(r_argv, writable). Skips the exe path 542 // (quoted or unquoted), takes the next token as argv[1] (the URL). Returns argc in eax (1 = no URL 543 // -> nish interactive; 2 = one-shot URL). r10=scan ptr, r9=ARGV_ARR, ecx=byte. All-volatile regs. 544 let r_build_argv: i64 = _nsh_rva(a) 545 let av_lo: i64 = (NSH_IMGBASE + r_argv) & 0xFFFFFFFF 546 let av_hi: i64 = (NSH_IMGBASE + r_argv) / 4294967296 547 _w8(buf,a+0,0x48);_w8(buf,a+1,0x83);_w8(buf,a+2,0xEC);_w8(buf,a+3,0x28) // sub rsp,0x28 548 _w8(buf,a+4,0xFF);_w8(buf,a+5,0x15);_w32(buf,a+6, iat_gcl - _nsh_rva(a+10)) // call [GetCommandLineA] 549 _w8(buf,a+10,0x49);_w8(buf,a+11,0x89);_w8(buf,a+12,0xC2) // mov r10,rax 550 _w8(buf,a+13,0x49);_w8(buf,a+14,0xB9);_w32(buf,a+15,av_lo);_w32(buf,a+19,av_hi) // mov r9,ARGV_VA 551 _w8(buf,a+23,0x49);_w8(buf,a+24,0x89);_w8(buf,a+25,0x01) // mov [r9],rax (argv0) 552 _w8(buf,a+26,0x41);_w8(buf,a+27,0x0F);_w8(buf,a+28,0xB6);_w8(buf,a+29,0x0A) // movzx ecx,[r10] 553 _w8(buf,a+30,0x80);_w8(buf,a+31,0xF9);_w8(buf,a+32,0x22) // cmp cl,'"' 554 _w8(buf,a+33,0x75);_w8(buf,a+34,0x1A) // jne U0 (+26) 555 _w8(buf,a+35,0x49);_w8(buf,a+36,0xFF);_w8(buf,a+37,0xC2) // inc r10 556 _w8(buf,a+38,0x41);_w8(buf,a+39,0x0F);_w8(buf,a+40,0xB6);_w8(buf,a+41,0x0A) // Q0: movzx ecx,[r10] 557 _w8(buf,a+42,0x84);_w8(buf,a+43,0xC9) // test cl,cl 558 _w8(buf,a+44,0x74);_w8(buf,a+45,0x55) // je DONE1 (+85) 559 _w8(buf,a+46,0x80);_w8(buf,a+47,0xF9);_w8(buf,a+48,0x22) // cmp cl,'"' 560 _w8(buf,a+49,0x74);_w8(buf,a+50,0x05) // je Q0E (+5) 561 _w8(buf,a+51,0x49);_w8(buf,a+52,0xFF);_w8(buf,a+53,0xC2) // inc r10 562 _w8(buf,a+54,0xEB);_w8(buf,a+55,0xEE) // jmp Q0 (-18) 563 _w8(buf,a+56,0x49);_w8(buf,a+57,0xFF);_w8(buf,a+58,0xC2) // Q0E: inc r10 564 _w8(buf,a+59,0xEB);_w8(buf,a+60,0x17) // jmp WS (+23) 565 _w8(buf,a+61,0x41);_w8(buf,a+62,0x0F);_w8(buf,a+63,0xB6);_w8(buf,a+64,0x0A) // U0: movzx ecx,[r10] 566 _w8(buf,a+65,0x84);_w8(buf,a+66,0xC9) // test cl,cl 567 _w8(buf,a+67,0x74);_w8(buf,a+68,0x3E) // je DONE1 (+62) 568 _w8(buf,a+69,0x80);_w8(buf,a+70,0xF9);_w8(buf,a+71,0x20) // cmp cl,' ' 569 _w8(buf,a+72,0x74);_w8(buf,a+73,0x0A) // je WS (+10) 570 _w8(buf,a+74,0x80);_w8(buf,a+75,0xF9);_w8(buf,a+76,0x09) // cmp cl,tab 571 _w8(buf,a+77,0x74);_w8(buf,a+78,0x05) // je WS (+5) 572 _w8(buf,a+79,0x49);_w8(buf,a+80,0xFF);_w8(buf,a+81,0xC2) // inc r10 573 _w8(buf,a+82,0xEB);_w8(buf,a+83,0xE9) // jmp U0 (-23) 574 _w8(buf,a+84,0x41);_w8(buf,a+85,0x0F);_w8(buf,a+86,0xB6);_w8(buf,a+87,0x0A) // WS: movzx ecx,[r10] 575 _w8(buf,a+88,0x80);_w8(buf,a+89,0xF9);_w8(buf,a+90,0x20) // cmp cl,' ' 576 _w8(buf,a+91,0x74);_w8(buf,a+92,0x07) // je WSADV (+7) 577 _w8(buf,a+93,0x80);_w8(buf,a+94,0xF9);_w8(buf,a+95,0x09) // cmp cl,tab 578 _w8(buf,a+96,0x74);_w8(buf,a+97,0x02) // je WSADV (+2) 579 _w8(buf,a+98,0xEB);_w8(buf,a+99,0x05) // jmp TOK (+5) 580 _w8(buf,a+100,0x49);_w8(buf,a+101,0xFF);_w8(buf,a+102,0xC2) // WSADV: inc r10 581 _w8(buf,a+103,0xEB);_w8(buf,a+104,0xEB) // jmp WS (-21) 582 _w8(buf,a+105,0x84);_w8(buf,a+106,0xC9) // TOK: test cl,cl 583 _w8(buf,a+107,0x74);_w8(buf,a+108,0x16) // je DONE1 (+22) 584 _w8(buf,a+109,0x4D);_w8(buf,a+110,0x89);_w8(buf,a+111,0x51);_w8(buf,a+112,0x08) // mov [r9+8],r10 (argv1) 585 _w8(buf,a+113,0x49);_w8(buf,a+114,0xC7);_w8(buf,a+115,0x41);_w8(buf,a+116,0x10);_w32(buf,a+117,0) // mov qword[r9+16],0 586 _w8(buf,a+121,0xB8);_w32(buf,a+122,2) // mov eax,2 587 _w8(buf,a+126,0x48);_w8(buf,a+127,0x83);_w8(buf,a+128,0xC4);_w8(buf,a+129,0x28) // add rsp,0x28 588 _w8(buf,a+130,0xC3) // ret 589 _w8(buf,a+131,0x49);_w8(buf,a+132,0xC7);_w8(buf,a+133,0x41);_w8(buf,a+134,0x08);_w32(buf,a+135,0) // DONE1: mov qword[r9+8],0 590 _w8(buf,a+139,0xB8);_w32(buf,a+140,1) // mov eax,1 591 _w8(buf,a+144,0x48);_w8(buf,a+145,0x83);_w8(buf,a+146,0xC4);_w8(buf,a+147,0x28) // add rsp,0x28 592 _w8(buf,a+148,0xC3) // ret 593 a = a + 149 594 595 if (a - NSH_FOFF_TEXT) > text_fsz { return 0 - 201 } 596 597 // ===== entry stub @ FOFF_TEXT (40 bytes): init Winsock, build argv from the command line, 598 // then call main(argc, argv) ===== 599 let argv_lo: i64 = (NSH_IMGBASE + r_argv) & 0xFFFFFFFF 600 let argv_hi: i64 = (NSH_IMGBASE + r_argv) / 4294967296 601 let t: i64 = NSH_FOFF_TEXT 602 _w8(buf,t+0,0x48);_w8(buf,t+1,0x83);_w8(buf,t+2,0xEC);_w8(buf,t+3,0x28) // sub rsp,0x28 603 _w8(buf,t+4,0xE8);_w32(buf,t+5, r_wsa - _nsh_rva(t + 9)) // call WSAStartup-init 604 _w8(buf,t+9,0xE8);_w32(buf,t+10, r_build_argv - _nsh_rva(t + 14)) // call build_argv -> eax=argc 605 _w8(buf,t+14,0x89);_w8(buf,t+15,0xC7) // mov edi,eax (argc) 606 _w8(buf,t+16,0x48);_w8(buf,t+17,0xBE);_w32(buf,t+18,argv_lo);_w32(buf,t+22,argv_hi) // mov rsi,ARGV_ARR 607 _w8(buf,t+26,0xE8);_w32(buf,t+27,9 + off[0]) // call main 608 _w8(buf,t+31,0x89);_w8(buf,t+32,0xC1) // mov ecx,eax 609 _w8(buf,t+33,0xFF);_w8(buf,t+34,0x15);_w32(buf,t+35, iat_exit - _nsh_rva(t + 39)) // call ExitProcess 610 _w8(buf,t+39,0xCC) // int3 611 612 // ===== redirects ===== 613 _nsh_redir(buf, off[1], r_halloc) // sys_mmap 614 _nsh_redir(buf, off[2], r_write) // sys_write (console | send) 615 _nsh_redir(buf, off[3], r_exit) // sys_exit 616 _nsh_redir(buf, off[4], r_readfile) // sys_read_file 617 _nsh_redir(buf, off[5], r_nowsec) // sys_now_realtime_sec 618 _nsh_redir(buf, off[6], r_openat) // sys_openat_rd 619 _nsh_redir(buf, off[7], r_read) // sys_read (stdin | recv) 620 _nsh_redir(buf, off[8], r_close) // sys_close -> closesocket 621 _nsh_redir(buf, off[9], r_socket) // sys_socket 622 _nsh_redir(buf, off[10], r_connect) // sys_connect 623 _nsh_redir(buf, off[11], r_sendto) // sys_sendto 624 _nsh_redir(buf, off[12], r_recvfrom) // sys_recvfrom 625 _nsh_redir(buf, off[13], r_zero) // sys_setsockopt -> 0 626 _nsh_redir(buf, off[14], r_zero) // sys_clock_gettime_real -> 0 (unreached) 627 _nsh_redir(buf, off[15], r_mono) // sys_clock_gettime_mono -> GetSystemTimeAsFileTime (native ms clock) 628 629 // ===== .idata (kernel32{10} + ws2_32{8}) ===== 630 let d: i64 = foff_idata 631 var nf: i64 = d + NSH_NAMES 632 let rn_exit: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "ExitProcess") 633 let rn_gph: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "GetProcessHeap") 634 let rn_ha: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "HeapAlloc") 635 let rn_gsh: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "GetStdHandle") 636 let rn_wf: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "WriteFile") 637 let rn_rf: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "ReadFile") 638 let rn_cfa: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "CreateFileA") 639 let rn_gfs: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "GetFileSizeEx") 640 let rn_gst: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "GetSystemTimeAsFileTime") 641 let rn_ch: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "CloseHandle") 642 let rn_gcl: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "GetCommandLineA") 643 let rn_wsa: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "WSAStartup") 644 let rn_sock: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "socket") 645 let rn_conn: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "connect") 646 let rn_send: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "send") 647 let rn_recv: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "recv") 648 let rn_sto: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "sendto") 649 let rn_rfr: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "recvfrom") 650 let rn_cls: i64 = rva_idata + (nf - d); nf = _nsh_put_name(buf, nf, "closesocket") 651 let rn_kdll: i64 = rva_idata + (nf - d); nf = _nsh_put_str(buf, nf, "kernel32.dll") 652 let rn_wdll: i64 = rva_idata + (nf - d); nf = _nsh_put_str(buf, nf, "ws2_32.dll") 653 654 // descriptors 655 _w32(buf, d + NSH_DESC_K + 0, rva_idata + NSH_INT_K); _w32(buf, d + NSH_DESC_K + 12, rn_kdll); _w32(buf, d + NSH_DESC_K + 16, rva_idata + NSH_IAT_K) 656 _w32(buf, d + NSH_DESC_W + 0, rva_idata + NSH_INT_W); _w32(buf, d + NSH_DESC_W + 12, rn_wdll); _w32(buf, d + NSH_DESC_W + 16, rva_idata + NSH_IAT_W) 657 // kernel32 INT + IAT 658 _w64(buf, d+NSH_INT_K+0, rn_exit,0); _w64(buf, d+NSH_IAT_K+0, rn_exit,0) 659 _w64(buf, d+NSH_INT_K+8, rn_gph,0); _w64(buf, d+NSH_IAT_K+8, rn_gph,0) 660 _w64(buf, d+NSH_INT_K+16, rn_ha,0); _w64(buf, d+NSH_IAT_K+16, rn_ha,0) 661 _w64(buf, d+NSH_INT_K+24, rn_gsh,0); _w64(buf, d+NSH_IAT_K+24, rn_gsh,0) 662 _w64(buf, d+NSH_INT_K+32, rn_wf,0); _w64(buf, d+NSH_IAT_K+32, rn_wf,0) 663 _w64(buf, d+NSH_INT_K+40, rn_rf,0); _w64(buf, d+NSH_IAT_K+40, rn_rf,0) 664 _w64(buf, d+NSH_INT_K+48, rn_cfa,0); _w64(buf, d+NSH_IAT_K+48, rn_cfa,0) 665 _w64(buf, d+NSH_INT_K+56, rn_gfs,0); _w64(buf, d+NSH_IAT_K+56, rn_gfs,0) 666 _w64(buf, d+NSH_INT_K+64, rn_gst,0); _w64(buf, d+NSH_IAT_K+64, rn_gst,0) 667 _w64(buf, d+NSH_INT_K+72, rn_ch,0); _w64(buf, d+NSH_IAT_K+72, rn_ch,0) 668 _w64(buf, d+NSH_INT_K+80, rn_gcl,0); _w64(buf, d+NSH_IAT_K+80, rn_gcl,0) 669 _w64(buf, d+NSH_INT_K+88, 0,0); _w64(buf, d+NSH_IAT_K+88, 0,0) 670 // ws2_32 INT + IAT 671 _w64(buf, d+NSH_INT_W+0, rn_wsa,0); _w64(buf, d+NSH_IAT_W+0, rn_wsa,0) 672 _w64(buf, d+NSH_INT_W+8, rn_sock,0); _w64(buf, d+NSH_IAT_W+8, rn_sock,0) 673 _w64(buf, d+NSH_INT_W+16, rn_conn,0); _w64(buf, d+NSH_IAT_W+16, rn_conn,0) 674 _w64(buf, d+NSH_INT_W+24, rn_send,0); _w64(buf, d+NSH_IAT_W+24, rn_send,0) 675 _w64(buf, d+NSH_INT_W+32, rn_recv,0); _w64(buf, d+NSH_IAT_W+32, rn_recv,0) 676 _w64(buf, d+NSH_INT_W+40, rn_sto,0); _w64(buf, d+NSH_IAT_W+40, rn_sto,0) 677 _w64(buf, d+NSH_INT_W+48, rn_rfr,0); _w64(buf, d+NSH_IAT_W+48, rn_rfr,0) 678 _w64(buf, d+NSH_INT_W+56, rn_cls,0); _w64(buf, d+NSH_IAT_W+56, rn_cls,0) 679 _w64(buf, d+NSH_INT_W+64, 0,0); _w64(buf, d+NSH_IAT_W+64, 0,0) 680 681 return NX_PE_OK 682} 683 684func main() -> i64 { 685 let lenbox: *i64 = sys_mmap(16) as *i64 686 let src: *u8 = sys_read_file("/tmp/nxwin.s" as *u8, lenbox) 687 if (src as i64) == 0 { return 1 } 688 let n: i64 = lenbox[0] 689 if n <= 0 { return 2 } 690 691 let code: *u8 = sys_mmap(NSH_CODE_CAP) 692 let off: *i64 = sys_mmap(32 * 8) as *i64 693 var z: i64 = 0 694 while z < 16 { off[z] = 0 - 1; z = z + 1 } 695 let code_len: i64 = nsh_assemble(src, n, code, NSH_CODE_CAP, off) 696 if code_len < 0 { return 3 } 697 if off[0] < 0 { return 4 } 698 699 let span: i64 = NSH_STUB_LEN + code_len + NSH_THUNK_SLACK 700 let text_fsz: i64 = _nsh_align(span, 0x200) 701 let rva_idata: i64 = 0x1000 + _nsh_align(span, 0x1000) 702 let file_size: i64 = NSH_FOFF_TEXT + text_fsz + NSH_IDATA_FSZ 703 704 let buf: *u8 = sys_mmap(file_size) 705 let rc: i64 = nsh_emit_pe(buf, code, code_len, off, file_size, text_fsz, rva_idata) 706 if rc != NX_PE_OK { return 5 } 707 708 let outp: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_offc/nishi_fetch.exe" as *u8 709 if nx_pe_write_to_file(outp, buf, file_size) != NX_PE_OK { return 70 } 710 711 let msg: *u8 = "[substrate] Nishi fetch-engine PE written: _offc/nishi_fetch.exe\n" as *u8 712 sys_write(1, msg, 65) 713 return 0 714}