code wiki / _hdl_build / nx_pe_dll_com_gate.nx
nx_pe_dll_com_gate.nx source
↩ module page · 133 lines · 8379 B
1// nx_pe_dll_com_gate.nx -- de-risk the ENTIRE D3D11 shim surface: a sovereign DLL that returns a COM-STYLE OBJECT
2// (pointer whose first field is a vtable of function pointers) that a foreign Windows process dispatches methods through.
3// This is EXACTLY the shape of D3D11: D3D11CreateDevice returns ID3D11Device* and the game calls dev->lpVtbl->Method(dev,..).
4// If a foreign C process can create our object and call methods via its vtable + read object state through `this`, the
5// d3d11.dll shim is clearly buildable -- only API breadth remains. The export `nishi_create_device` builds the object +
6// vtable at RUNTIME with RIP-relative LEA (position-independent: no absolute data pointers, works at ANY base, needs no
7// .reloc). Object: {vtbl*, magic=1000}. Methods: get_magic(this)->*this.magic ; add(this,a,b)->magic+a+b. 100% NishiLang
8// PE bytes; C harness = external oracle (Windows' own loader + call). license_tier: ORIGINAL expect_exit: 0
9import "nx_syscalls.nx"
10
11func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
12func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 }
13func px2(v: i64) -> i64 { let d: *u8="0123456789abcdef" as *u8; let b: *u8=sys_mmap(4) as *u8; b[0]=d[(v>>4)&15]; b[1]=d[v&15]; sys_write(1,b,2); return 0 }
14
15func w8(buf: *u8, off: i64, v: i64) -> i64 { buf[off] = (v & 255) as u8; return 0 }
16func w16(buf: *u8, off: i64, v: i64) -> i64 { buf[off]=(v&255) as u8; buf[off+1]=((v>>8)&255) as u8; return 0 }
17func w32(buf: *u8, off: i64, v: i64) -> i64 { buf[off]=(v&255) as u8; buf[off+1]=((v>>8)&255) as u8; buf[off+2]=((v>>16)&255) as u8; buf[off+3]=((v>>24)&255) as u8; return 0 }
18func wstr(buf: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ buf[off+i]=s[i]; i=i+1 } buf[off+i]=0 as u8; return i+1 }
19
20func main() -> i64 {
21 hw("=== nx_pe_dll_com_gate -- sovereign DLL returns a COM-style object; foreign process dispatches via vtable ===\n" as *u8)
22 var fails: i64 = 0
23 let N: i64 = 0x800
24 let b: *u8 = sys_mmap(N) // zeroed
25
26 // ---- DOS + PE sig ----
27 w16(b, 0, 0x5A4D); w32(b, 0x3C, 0x80); w32(b, 0x80, 0x00004550)
28 // ---- COFF @ 0x84 ----
29 w16(b, 0x84 + 0, 0x8664)
30 w16(b, 0x84 + 2, 3) // .text + .data + .edata
31 w16(b, 0x84 + 16, 0xF0)
32 w16(b, 0x84 + 18, 0x2022) // EXEC|LARGE_ADDR|DLL
33 // ---- Optional header @ 0x98 ----
34 let O: i64 = 0x98
35 w16(b, O + 0, 0x020B)
36 w8(b, O + 2, 1)
37 w32(b, O + 4, 0x200) // SizeOfCode
38 w32(b, O + 8, 0x400) // SizeOfInitializedData (.data + .edata)
39 w32(b, O + 16, 0) // AddressOfEntryPoint=0 (no DllMain)
40 w32(b, O + 20, 0x1000) // BaseOfCode
41 w32(b, O + 24, 0x80000000) // ImageBase 0x180000000 (code is base-independent anyway)
42 w32(b, O + 28, 0x1)
43 w32(b, O + 32, 0x1000) // SectionAlignment
44 w32(b, O + 36, 0x200) // FileAlignment
45 w16(b, O + 40, 6); w16(b, O + 48, 6)
46 w32(b, O + 56, 0x4000) // SizeOfImage (hdr+.text+.data+.edata)
47 w32(b, O + 60, 0x200) // SizeOfHeaders
48 w16(b, O + 68, 3) // Subsystem CONSOLE
49 w16(b, O + 70, 0) // DllCharacteristics
50 w32(b, O + 72, 0x100000); w32(b, O + 80, 0x1000); w32(b, O + 88, 0x100000); w32(b, O + 96, 0x1000)
51 w32(b, O + 108, 16)
52 w32(b, O + 112 + 0, 0x3000) // DataDir[0] Export RVA
53 w32(b, O + 112 + 4, 0x54) // Export size
54
55 // ---- Section table @ 0x188 ----
56 let S: i64 = 0x188
57 wstr(b, S + 0, ".text\x00" as *u8); w32(b, S + 8, 0x41); w32(b, S + 12, 0x1000); w32(b, S + 16, 0x200); w32(b, S + 20, 0x200); w32(b, S + 36, 0x60000020)
58 wstr(b, S + 40, ".data\x00" as *u8); w32(b, S + 48, 0x20); w32(b, S + 52, 0x2000); w32(b, S + 56, 0x200); w32(b, S + 60, 0x400); w32(b, S + 76, 0xC0000040)
59 wstr(b, S + 80, ".edata\x00" as *u8);w32(b, S + 88, 0x54); w32(b, S + 92, 0x3000); w32(b, S + 96, 0x200); w32(b, S + 100, 0x600); w32(b, S + 116, 0x40000040)
60
61 // ================= .text @ file 0x200 =================
62 // method_magic (RVA 0x1000): mov eax,[rcx+8] ; ret
63 w8(b,0x200,0x8B); w8(b,0x201,0x41); w8(b,0x202,0x08); w8(b,0x203,0xC3)
64 // method_add (RVA 0x1004): mov eax,[rcx+8] ; add eax,edx ; add eax,r8d ; ret
65 w8(b,0x204,0x8B); w8(b,0x205,0x41); w8(b,0x206,0x08)
66 w8(b,0x207,0x01); w8(b,0x208,0xD0)
67 w8(b,0x209,0x44); w8(b,0x20A,0x01); w8(b,0x20B,0xC0)
68 w8(b,0x20C,0xC3)
69 // pad to RVA 0x1010
70 w8(b,0x20D,0xCC); w8(b,0x20E,0xCC); w8(b,0x20F,0xCC)
71 // nishi_create_device (RVA 0x1010, file 0x210): RIP-relative build of {vtbl,magic} + vtable[get_magic,add]
72 // I0 lea rax,[rip+0xFF9] -> &vtable(0x2010)
73 w8(b,0x210,0x48); w8(b,0x211,0x8D); w8(b,0x212,0x05); w32(b,0x213,0xFF9)
74 // I1 lea rcx,[rip-0x1E] -> &method_magic(0x1000)
75 w8(b,0x217,0x48); w8(b,0x218,0x8D); w8(b,0x219,0x0D); w32(b,0x21A,0xFFFFFFE2)
76 // I2 mov [rax],rcx (vtable[0]=&method_magic)
77 w8(b,0x21E,0x48); w8(b,0x21F,0x89); w8(b,0x220,0x08)
78 // I3 lea rcx,[rip-0x24] -> &method_add(0x1004)
79 w8(b,0x221,0x48); w8(b,0x222,0x8D); w8(b,0x223,0x0D); w32(b,0x224,0xFFFFFFDC)
80 // I4 mov [rax+8],rcx (vtable[1]=&method_add)
81 w8(b,0x228,0x48); w8(b,0x229,0x89); w8(b,0x22A,0x48); w8(b,0x22B,0x08)
82 // I5 lea rcx,[rip+0xFCD] -> &object(0x2000)
83 w8(b,0x22C,0x48); w8(b,0x22D,0x8D); w8(b,0x22E,0x0D); w32(b,0x22F,0xFCD)
84 // I6 mov [rcx],rax (object.vtbl=&vtable)
85 w8(b,0x233,0x48); w8(b,0x234,0x89); w8(b,0x235,0x01)
86 // I7 mov dword [rcx+8],1000
87 w8(b,0x236,0xC7); w8(b,0x237,0x41); w8(b,0x238,0x08); w32(b,0x239,1000)
88 // I8 mov rax,rcx ; I9 ret
89 w8(b,0x23D,0x48); w8(b,0x23E,0x89); w8(b,0x23F,0xC8); w8(b,0x240,0xC3)
90
91 // ================= .edata @ file 0x600 (RVA 0x3000) =================
92 let E: i64 = 0x600
93 w32(b, E + 12, 0x3046) // Name RVA -> dllname
94 w32(b, E + 16, 1) // Base
95 w32(b, E + 20, 1) // NumberOfFunctions
96 w32(b, E + 24, 1) // NumberOfNames
97 w32(b, E + 28, 0x3028) // AddressOfFunctions
98 w32(b, E + 32, 0x302C) // AddressOfNames
99 w32(b, E + 36, 0x3030) // AddressOfNameOrdinals
100 w32(b, E + 0x28, 0x1010) // func[0] RVA -> nishi_create_device
101 w32(b, E + 0x2C, 0x3032) // name[0] RVA -> "nishi_create_device"
102 w16(b, E + 0x30, 0) // ordinal[0]
103 wstr(b, E + 0x32, "nishi_create_device\x00" as *u8)
104 wstr(b, E + 0x46, "nishigpu2.dll\x00" as *u8)
105
106 // ---- write ----
107 let fd: i64 = sys_openat_wr("knowledge/nishigpu2.dll\x00" as *u8, 0x1a4)
108 if fd < 0 { hw("FAIL open\n" as *u8); sys_exit(1); return 1 }
109 let wrote: i64 = sys_write(fd, b, N)
110 sys_close(fd)
111
112 hw(" wrote "); pn(wrote); hw(" bytes to knowledge/nishigpu2.dll\n" as *u8)
113 hw(" create_device[0..3]="); px2(b[0x210] as i64); px2(b[0x211] as i64); px2(b[0x212] as i64); px2(b[0x213] as i64); hw("\n" as *u8)
114
115 var t1: i64 = 0
116 if (b[0] as i64) == 0x4D { if (b[0x84+18] as i64) == 0x22 { t1 = 1 } }
117 if t1 == 1 { hw("T1 PASS MZ + DLL characteristic\n" as *u8) } else { fails=fails+1; hw("T1 FAIL\n" as *u8) }
118 var t2: i64 = 0
119 if wrote == N { t2 = 1 }
120 if t2 == 1 { hw("T2 PASS full image (0x800) written\n" as *u8) } else { fails=fails+1; hw("T2 FAIL\n" as *u8) }
121 var t3: i64 = 0
122 if (b[0x600 + 0x32] as i64) == 110 { if (b[0x600+0x33] as i64) == 105 { t3 = 1 } } // 'ni'
123 if t3 == 1 { hw("T3 PASS export 'nishi_create_device' present\n" as *u8) } else { fails=fails+1; hw("T3 FAIL\n" as *u8) }
124 // T4 create_device begins with REX.W lea (48 8D 05)
125 var t4: i64 = 0
126 if (b[0x210] as i64)==0x48 { if (b[0x211] as i64)==0x8D { if (b[0x212] as i64)==0x05 { t4=1 } } }
127 if t4 == 1 { hw("T4 PASS create_device starts with RIP-relative lea (position-independent)\n" as *u8) } else { fails=fails+1; hw("T4 FAIL\n" as *u8) }
128
129 if fails == 0 { hw("NX-PE-DLL-COM verdict=GREEN -- sovereign COM-style DLL emitted; harness must create object + dispatch vtable\n" as *u8); sys_exit(0); return 0 }
130 hw("NX-PE-DLL-COM RED fails="); pn(fails); hw("\n" as *u8)
131 sys_exit(1)
132 return 1
133}