code wiki / (root) / nx_pe_container_win_ping.nx

nx_pe_container_win_ping.nx source

↩ module page · 218 lines · 14983 B

1// nx_pe_container_win.nx -- W4-a: a NISHI ORGAN runs as a Job-Object-governed, supervised container. 2// 3// Composes W2c (Job boundary + limit + CreateProcessW + Wait + GetExitCode + reap) with W3b-6 (a 4// realistic nxc2-compiled organ that runs entirely native). Same governed-run pipeline as W2c, but the 5// child workload is no longer `cmd.exe /c exit 7` -- it is our own Nishi organ `nx_win_compiled_organ.exe` 6// (allocate->fill->print->exit 88). So a sovereign Nishi organ now runs UNDER native Job-Object 7// governance and is reaped by a native supervisor -- the core of nx_container_win, no HCS/VM/Docker. 8// 9// 1. CreateJobObjectW(NULL,NULL) -> hJob 10// 2. SetInformationJobObject(hJob, 2, &basic{ActiveProcessLimit=8}, 0x40) (governance installed) 11// 3. AssignProcessToJobObject(hJob, (HANDLE)-1) (self joins the job) 12// 4. CreateProcessW(NULL,"nx_win_compiled_organ.exe",...,CREATE_NO_WINDOW,...,&si,&pi) (organ; auto-joins job) 13// 5. WaitForSingleObject(pi.hProcess, INFINITE) 14// 6. GetExitCodeProcess(pi.hProcess, &code) 15// 7. ExitProcess(code) 16// 17// CreateProcessW (lpApplicationName=NULL) resolves the bare filename via the app-load-directory search 18// rule: the supervisor exe and the organ exe both live in _offc, so "nx_win_compiled_organ.exe" is 19// found there. The command line is in the RW .data section (CreateProcessW may modify it). 20// 21// NO-FALSE-GREEN: the organ prints "NX\n" and exits 88. Supervisor exit == 88 proves it launched the 22// Nishi organ as a governed child and reaped its real exit code (cmd would never yield "NX"+88). The 23// organ's "NX" on the console proves the governed child actually executed. 24// 25// 7 kernel32 imports, identical proven .text/.idata to W2c (nx_pe_job_run_test); ONLY the .data command 26// line differs. Founded on nx_pe_writer.nx (hand byte-layout, tutor-scaffold). 27// lineage_id: substrate_pe_container_win_v1 (genealogy: win32_job_objects_2000 + runc_init_2014) 28 29import "nx_syscalls.nx" 30import "nx_hal.nx" 31import "nx_pe_writer.nx" 32 33const PE_CWIN_FILE_SIZE: i64 = 0x800 34 35// Write ASCII literal `s` as a UTF-16LE, NUL-terminated string into buf at `off`. Returns char count. 36func nxcw_put_utf16(buf: *u8, off: i64, s: *u8) -> i64 { 37 var i: i64 = 0 38 while s[i] != 0 { 39 _w16(buf, off + i * 2, s[i] as i64) 40 i = i + 1 41 } 42 _w16(buf, off + i * 2, 0) 43 return i 44} 45 46// IAT RVAs (same as W2c): CJO 0x3068 SIJO 0x3070 APTJ 0x3078 CPW 0x3080 WAIT 0x3088 GECP 0x3090 EXIT 0x3098. 47func nx_pe_emit_container(buf: *u8) -> i64 { 48 if (buf as i64) == 0 { return 0 - NX_PE_BAD_INPUT } 49 50 _w16(buf, 0, 0x5A4D) 51 _w32(buf, 0x3C, FOFF_PE_SIG) 52 _w32(buf, FOFF_PE_SIG, 0x00004550) 53 54 _w16(buf, FOFF_COFF + 0, PE_MACHINE_AMD64) 55 _w16(buf, FOFF_COFF + 2, 3) 56 _w16(buf, FOFF_COFF + 16, 0xF0) 57 _w16(buf, FOFF_COFF + 18, PE_CHAR_EXEC | PE_CHAR_LARGE_ADDR) 58 59 _w16(buf, FOFF_OPT + 0, PE_OH_MAGIC_PEPLUS) 60 _w8(buf, FOFF_OPT + 2, 1) 61 _w32(buf, FOFF_OPT + 4, 0x200) 62 _w32(buf, FOFF_OPT + 8, 0x400) 63 _w32(buf, FOFF_OPT + 16, PE_HELLO_RVA_TEXT) 64 _w32(buf, FOFF_OPT + 20, PE_HELLO_RVA_TEXT) 65 _w64(buf, FOFF_OPT + 24, IMG_BASE_LO, IMG_BASE_HI) 66 _w32(buf, FOFF_OPT + 32, 0x1000) 67 _w32(buf, FOFF_OPT + 36, 0x200) 68 _w16(buf, FOFF_OPT + 40, 6) 69 _w16(buf, FOFF_OPT + 48, 6) 70 _w32(buf, FOFF_OPT + 56, 0x4000) 71 _w32(buf, FOFF_OPT + 60, 0x200) 72 _w16(buf, FOFF_OPT + 68, PE_SUBSYSTEM_CONSOLE) 73 _w64(buf, FOFF_OPT + 72, 0x100000, 0) 74 _w64(buf, FOFF_OPT + 80, 0x1000, 0) 75 _w64(buf, FOFF_OPT + 88, 0x100000, 0) 76 _w64(buf, FOFF_OPT + 96, 0x1000, 0) 77 _w32(buf, FOFF_OPT + 108, 16) 78 _w32(buf, FOFF_OPT + 112 + 8, PE_HELLO_RVA_IDATA) 79 _w32(buf, FOFF_OPT + 112 + 12, 0x28) 80 81 _emit_section_header(buf, FOFF_SECT_TBL, 46, 116, 101, 120, 116, 0, 0, 0, 0x100, PE_HELLO_RVA_TEXT, 0x200, PE_HELLO_FOFF_TEXT, PE_SECT_CODE_X_R) 82 _emit_section_header(buf, FOFF_SECT_TBL + 40, 46, 100, 97, 116, 97, 0, 0, 0, 0x40, PE_HELLO_RVA_RDATA, 0x200, PE_HELLO_FOFF_RDATA, PE_SECT_DATA_RW) 83 _emit_section_header(buf, FOFF_SECT_TBL + 80, 46, 105, 100, 97, 116, 97, 0, 0, 0x4B, PE_HELLO_RVA_IDATA, 0x200, PE_HELLO_FOFF_IDATA, PE_SECT_DATA_R) 84 _w32(buf, FOFF_SECT_TBL + 80 + 8, 0x14B) 85 86 // ===== .text (identical to W2c -- proven governed-run pipeline) ===== 87 let t: i64 = PE_HELLO_FOFF_TEXT 88 _w8(buf, t+0, 0x48); _w8(buf, t+1, 0x81); _w8(buf, t+2, 0xEC); _w32(buf, t+3, 0x138) 89 _w8(buf, t+7, 0x31); _w8(buf, t+8, 0xC0) 90 _w8(buf, t+9, 0x48); _w8(buf, t+10, 0x8D); _w8(buf, t+11, 0x7C); _w8(buf, t+12, 0x24); _w8(buf, t+13, 0x58) 91 _w8(buf, t+14, 0xB9); _w32(buf, t+15, 25) // zero 25 qwords (covers PROCESS_INFORMATION + exitCode -> launch-fail = deterministic exit 0) 92 _w8(buf, t+19, 0xF3); _w8(buf, t+20, 0x48); _w8(buf, t+21, 0xAB) 93 _w8(buf, t+22, 0xC7); _w8(buf, t+23, 0x44); _w8(buf, t+24, 0x24); _w8(buf, t+25, 0x58); _w32(buf, t+26, 0x68) 94 _w8(buf, t+30, 0x31); _w8(buf, t+31, 0xC9); _w8(buf, t+32, 0x31); _w8(buf, t+33, 0xD2) 95 _w8(buf, t+34, 0xFF); _w8(buf, t+35, 0x15); _w32(buf, t+36, 0x2040) 96 _w8(buf, t+40, 0x48); _w8(buf, t+41, 0x89); _w8(buf, t+42, 0x44); _w8(buf, t+43, 0x24); _w8(buf, t+44, 0x50) 97 _w8(buf, t+45, 0xC7); _w8(buf, t+46, 0x84); _w8(buf, t+47, 0x24); _w32(buf, t+48, 0xE8); _w32(buf, t+52, 8) 98 _w8(buf, t+56, 0xC7); _w8(buf, t+57, 0x84); _w8(buf, t+58, 0x24); _w32(buf, t+59, 0x100); _w32(buf, t+63, 8) 99 _w8(buf, t+67, 0x48); _w8(buf, t+68, 0x8B); _w8(buf, t+69, 0x4C); _w8(buf, t+70, 0x24); _w8(buf, t+71, 0x50) 100 _w8(buf, t+72, 0xBA); _w32(buf, t+73, 2) 101 _w8(buf, t+77, 0x4C); _w8(buf, t+78, 0x8D); _w8(buf, t+79, 0x84); _w8(buf, t+80, 0x24); _w32(buf, t+81, 0xD8) 102 _w8(buf, t+85, 0x41); _w8(buf, t+86, 0xB9); _w32(buf, t+87, 0x40) 103 _w8(buf, t+91, 0xFF); _w8(buf, t+92, 0x15); _w32(buf, t+93, 0x200F) 104 _w8(buf, t+97, 0x48); _w8(buf, t+98, 0x8B); _w8(buf, t+99, 0x4C); _w8(buf, t+100, 0x24); _w8(buf, t+101, 0x50) 105 _w8(buf, t+102, 0x48); _w8(buf, t+103, 0xC7); _w8(buf, t+104, 0xC2); _w8(buf, t+105, 0xFF); _w8(buf, t+106, 0xFF); _w8(buf, t+107, 0xFF); _w8(buf, t+108, 0xFF) 106 _w8(buf, t+109, 0xFF); _w8(buf, t+110, 0x15); _w32(buf, t+111, 0x2005) 107 _w8(buf, t+115, 0x31); _w8(buf, t+116, 0xC9) 108 _w8(buf, t+117, 0x48); _w8(buf, t+118, 0x8D); _w8(buf, t+119, 0x15); _w32(buf, t+120, 0xF84) 109 _w8(buf, t+124, 0x45); _w8(buf, t+125, 0x31); _w8(buf, t+126, 0xC0) 110 _w8(buf, t+127, 0x45); _w8(buf, t+128, 0x31); _w8(buf, t+129, 0xC9) 111 _w8(buf, t+130, 0xC7); _w8(buf, t+131, 0x44); _w8(buf, t+132, 0x24); _w8(buf, t+133, 0x20); _w32(buf, t+134, 0) 112 _w8(buf, t+138, 0xC7); _w8(buf, t+139, 0x44); _w8(buf, t+140, 0x24); _w8(buf, t+141, 0x28); _w32(buf, t+142, 0x08000000) 113 _w8(buf, t+146, 0x48); _w8(buf, t+147, 0xC7); _w8(buf, t+148, 0x44); _w8(buf, t+149, 0x24); _w8(buf, t+150, 0x30); _w32(buf, t+151, 0) 114 _w8(buf, t+155, 0x48); _w8(buf, t+156, 0xC7); _w8(buf, t+157, 0x44); _w8(buf, t+158, 0x24); _w8(buf, t+159, 0x38); _w32(buf, t+160, 0) 115 _w8(buf, t+164, 0x48); _w8(buf, t+165, 0x8D); _w8(buf, t+166, 0x44); _w8(buf, t+167, 0x24); _w8(buf, t+168, 0x58) 116 _w8(buf, t+169, 0x48); _w8(buf, t+170, 0x89); _w8(buf, t+171, 0x44); _w8(buf, t+172, 0x24); _w8(buf, t+173, 0x40) 117 _w8(buf, t+174, 0x48); _w8(buf, t+175, 0x8D); _w8(buf, t+176, 0x84); _w8(buf, t+177, 0x24); _w32(buf, t+178, 0xC0) 118 _w8(buf, t+182, 0x48); _w8(buf, t+183, 0x89); _w8(buf, t+184, 0x44); _w8(buf, t+185, 0x24); _w8(buf, t+186, 0x48) 119 _w8(buf, t+187, 0xFF); _w8(buf, t+188, 0x15); _w32(buf, t+189, 0x1FBF) 120 _w8(buf, t+193, 0x48); _w8(buf, t+194, 0x8B); _w8(buf, t+195, 0x8C); _w8(buf, t+196, 0x24); _w32(buf, t+197, 0xC0) 121 _w8(buf, t+201, 0xBA); _w8(buf, t+202, 0xFF); _w8(buf, t+203, 0xFF); _w8(buf, t+204, 0xFF); _w8(buf, t+205, 0xFF) 122 _w8(buf, t+206, 0xFF); _w8(buf, t+207, 0x15); _w32(buf, t+208, 0x1FB4) 123 // ===== M1a RESTART-LOOP TAIL: child died -> close both handles, backoff, RESPAWN (never exits) ===== 124 // Replaces the one-shot GetExitCodeProcess+ExitProcess. rcx is volatile (clobbered by WaitForSingleObject) 125 // so hProcess/hThread are re-loaded from the PROCESS_INFORMATION at [rsp+0xC0]/[rsp+0xC8]. Slot 6 of the IAT 126 // (RVA 0x3090, was GECP) is now CloseHandle; slot 7 (0x3098, was ExitProcess) is now Sleep. The jmp targets 127 // L = t+115 (the CreateProcessW argument setup) so each iteration re-spawns the governed child under the SAME 128 // Job Object. 1000ms fixed backoff = a rate cap (<=1 respawn/s) so a crash-looping child cannot peg the CPU. 129 _w8(buf, t+212, 0x48); _w8(buf, t+213, 0x8B); _w8(buf, t+214, 0x8C); _w8(buf, t+215, 0x24); _w32(buf, t+216, 0xC0) // mov rcx,[rsp+0xC0] (hProcess) 130 _w8(buf, t+220, 0xFF); _w8(buf, t+221, 0x15); _w32(buf, t+222, 0x1FAE) // call [CloseHandle] 131 _w8(buf, t+226, 0x48); _w8(buf, t+227, 0x8B); _w8(buf, t+228, 0x8C); _w8(buf, t+229, 0x24); _w32(buf, t+230, 0xC8) // mov rcx,[rsp+0xC8] (hThread) 132 _w8(buf, t+234, 0xFF); _w8(buf, t+235, 0x15); _w32(buf, t+236, 0x1FA0) // call [CloseHandle] 133 _w8(buf, t+240, 0xB9); _w32(buf, t+241, 1000) // mov ecx, 1000 (ms backoff) 134 _w8(buf, t+245, 0xFF); _w8(buf, t+246, 0x15); _w32(buf, t+247, 0x1F9D) // call [Sleep] 135 _w8(buf, t+251, 0xE9); _w32(buf, t+252, 0xFFFFFF73) // jmp L (t+115, respawn) 136 137 // ===== .data: child command line (UTF-16) -- the ONLY change vs W2c ===== 138 nxcw_put_utf16(buf, PE_HELLO_FOFF_RDATA, "ping -n 3 127.0.0.1" as *u8) 139 140 // ===== .idata (7 imports, identical to W2c) ===== 141 let d: i64 = PE_HELLO_FOFF_IDATA 142 _w32(buf, d+0, 0x3028) 143 _w32(buf, d+12, 0x313E) 144 _w32(buf, d+16, 0x3068) 145 _w64(buf, d+0x28, 0x30A8, 0) 146 _w64(buf, d+0x30, 0x30BC, 0) 147 _w64(buf, d+0x38, 0x30D6, 0) 148 _w64(buf, d+0x40, 0x30F2, 0) 149 _w64(buf, d+0x48, 0x3104, 0) 150 _w64(buf, d+0x50, 0x311A, 0) 151 _w64(buf, d+0x58, 0x3130, 0) 152 _w64(buf, d+0x60, 0, 0) 153 _w64(buf, d+0x68, 0x30A8, 0) 154 _w64(buf, d+0x70, 0x30BC, 0) 155 _w64(buf, d+0x78, 0x30D6, 0) 156 _w64(buf, d+0x80, 0x30F2, 0) 157 _w64(buf, d+0x88, 0x3104, 0) 158 _w64(buf, d+0x90, 0x311A, 0) 159 _w64(buf, d+0x98, 0x3130, 0) 160 _w64(buf, d+0xA0, 0, 0) 161 _w16(buf, d+0xA8, 0) 162 _w8(buf,d+0xAA,67);_w8(buf,d+0xAB,114);_w8(buf,d+0xAC,101);_w8(buf,d+0xAD,97);_w8(buf,d+0xAE,116);_w8(buf,d+0xAF,101) 163 _w8(buf,d+0xB0,74);_w8(buf,d+0xB1,111);_w8(buf,d+0xB2,98);_w8(buf,d+0xB3,79);_w8(buf,d+0xB4,98);_w8(buf,d+0xB5,106) 164 _w8(buf,d+0xB6,101);_w8(buf,d+0xB7,99);_w8(buf,d+0xB8,116);_w8(buf,d+0xB9,87);_w8(buf,d+0xBA,0) 165 _w16(buf, d+0xBC, 0) 166 _w8(buf,d+0xBE,83);_w8(buf,d+0xBF,101);_w8(buf,d+0xC0,116);_w8(buf,d+0xC1,73);_w8(buf,d+0xC2,110);_w8(buf,d+0xC3,102) 167 _w8(buf,d+0xC4,111);_w8(buf,d+0xC5,114);_w8(buf,d+0xC6,109);_w8(buf,d+0xC7,97);_w8(buf,d+0xC8,116);_w8(buf,d+0xC9,105) 168 _w8(buf,d+0xCA,111);_w8(buf,d+0xCB,110);_w8(buf,d+0xCC,74);_w8(buf,d+0xCD,111);_w8(buf,d+0xCE,98);_w8(buf,d+0xCF,79) 169 _w8(buf,d+0xD0,98);_w8(buf,d+0xD1,106);_w8(buf,d+0xD2,101);_w8(buf,d+0xD3,99);_w8(buf,d+0xD4,116);_w8(buf,d+0xD5,0) 170 _w16(buf, d+0xD6, 0) 171 _w8(buf,d+0xD8,65);_w8(buf,d+0xD9,115);_w8(buf,d+0xDA,115);_w8(buf,d+0xDB,105);_w8(buf,d+0xDC,103);_w8(buf,d+0xDD,110) 172 _w8(buf,d+0xDE,80);_w8(buf,d+0xDF,114);_w8(buf,d+0xE0,111);_w8(buf,d+0xE1,99);_w8(buf,d+0xE2,101);_w8(buf,d+0xE3,115) 173 _w8(buf,d+0xE4,115);_w8(buf,d+0xE5,84);_w8(buf,d+0xE6,111);_w8(buf,d+0xE7,74);_w8(buf,d+0xE8,111);_w8(buf,d+0xE9,98) 174 _w8(buf,d+0xEA,79);_w8(buf,d+0xEB,98);_w8(buf,d+0xEC,106);_w8(buf,d+0xED,101);_w8(buf,d+0xEE,99);_w8(buf,d+0xEF,116);_w8(buf,d+0xF0,0) 175 _w16(buf, d+0xF2, 0) 176 _w8(buf,d+0xF4,67);_w8(buf,d+0xF5,114);_w8(buf,d+0xF6,101);_w8(buf,d+0xF7,97);_w8(buf,d+0xF8,116);_w8(buf,d+0xF9,101) 177 _w8(buf,d+0xFA,80);_w8(buf,d+0xFB,114);_w8(buf,d+0xFC,111);_w8(buf,d+0xFD,99);_w8(buf,d+0xFE,101);_w8(buf,d+0xFF,115) 178 _w8(buf,d+0x100,115);_w8(buf,d+0x101,87);_w8(buf,d+0x102,0) 179 _w16(buf, d+0x104, 0) 180 _w8(buf,d+0x106,87);_w8(buf,d+0x107,97);_w8(buf,d+0x108,105);_w8(buf,d+0x109,116);_w8(buf,d+0x10A,70);_w8(buf,d+0x10B,111) 181 _w8(buf,d+0x10C,114);_w8(buf,d+0x10D,83);_w8(buf,d+0x10E,105);_w8(buf,d+0x10F,110);_w8(buf,d+0x110,103);_w8(buf,d+0x111,108) 182 _w8(buf,d+0x112,101);_w8(buf,d+0x113,79);_w8(buf,d+0x114,98);_w8(buf,d+0x115,106);_w8(buf,d+0x116,101);_w8(buf,d+0x117,99) 183 _w8(buf,d+0x118,116);_w8(buf,d+0x119,0) 184 _w16(buf, d+0x11A, 0) 185 _w8(buf,d+0x11C,67);_w8(buf,d+0x11D,108);_w8(buf,d+0x11E,111);_w8(buf,d+0x11F,115);_w8(buf,d+0x120,101);_w8(buf,d+0x121,72) 186 _w8(buf,d+0x122,97);_w8(buf,d+0x123,110);_w8(buf,d+0x124,100);_w8(buf,d+0x125,108);_w8(buf,d+0x126,101);_w8(buf,d+0x127,0) 187 _w8(buf,d+0x128,0);_w8(buf,d+0x129,0);_w8(buf,d+0x12A,0);_w8(buf,d+0x12B,0);_w8(buf,d+0x12C,0);_w8(buf,d+0x12D,0) 188 _w8(buf,d+0x12E,0) 189 _w16(buf, d+0x130, 0) 190 _w8(buf,d+0x132,83);_w8(buf,d+0x133,108);_w8(buf,d+0x134,101);_w8(buf,d+0x135,101);_w8(buf,d+0x136,112);_w8(buf,d+0x137,0) 191 _w8(buf,d+0x138,0);_w8(buf,d+0x139,0);_w8(buf,d+0x13A,0);_w8(buf,d+0x13B,0);_w8(buf,d+0x13C,0);_w8(buf,d+0x13D,0) 192 _w8(buf,d+0x13E,107);_w8(buf,d+0x13F,101);_w8(buf,d+0x140,114);_w8(buf,d+0x141,110);_w8(buf,d+0x142,101);_w8(buf,d+0x143,108) 193 _w8(buf,d+0x144,51);_w8(buf,d+0x145,50);_w8(buf,d+0x146,46);_w8(buf,d+0x147,100);_w8(buf,d+0x148,108);_w8(buf,d+0x149,108);_w8(buf,d+0x14A,0) 194 195 return NX_PE_OK 196} 197 198func main() -> i64 { 199 let buf: *u8 = nx_hal_alloc_pages(PE_CWIN_FILE_SIZE) 200 if (buf as i64) == 0 { return 1 } 201 let rc: i64 = nx_pe_emit_container(buf) 202 if rc != NX_PE_OK { return 2 } 203 if buf[0] != 0x4D { return 10 } 204 if buf[0x200] != 0x48 { return 12 } // .text starts 'sub rsp' (0x48) 205 if buf[0x400] != 0x70 { return 13 } // .data 'p' (first wchar of "ping ...") 206 if buf[0x6AA] != 0x43 { return 14 } // 'C' of CreateJobObjectW 207 if buf[0x2DC] != 0xFF { return 15 } // restart-loop: first CloseHandle call opcode (FF 15) 208 if buf[0x2FB] != 0xE9 { return 16 } // restart-loop: backward jmp opcode 209 if buf[0x71C] != 0x43 { return 17 } // 'C' of CloseHandle (IAT slot 6 name @ 0x311C -> foff 0x600+0x11C) 210 if buf[0x732] != 0x53 { return 18 } // 'S' of Sleep (IAT slot 7 name @ 0x3132 -> foff 0x600+0x132) 211 let p: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_offc/nx_pe_container_win_ping.exe" as *u8 212 if nx_pe_write_to_file(p, buf, PE_CWIN_FILE_SIZE) != NX_PE_OK { return 70 } 213 let msg: *u8 = "[substrate] Supervisor PE written: nx_pe_container_win_ping.exe (respawns ping child under Job; 1s backoff)\n" as *u8 214 var mn: i64 = 0 215 while msg[mn] != 0 { mn = mn + 1 } 216 sys_write(1, msg, mn) 217 return 0 218}