Pop Pop Ret Finder

If you’ve attempt to write an SEH Record exploit, you know that it could be a little time consuming to find a pop pop ret instruction sequence inside a module that has SafeSEH off. This is because first you’d need to find which modules, if any, has SafeSEH off, and then search the sequence within those memory address. You could find the pop instruction for most registers, like “pop esp”, “pop eax”, “pop edx”, etc. Also, theres a good chance you don’t know the opcodes for these, so you’d probably assemble each of them to figure out the opcodes and then proceed to search for matches individually. The most frustrating part is that, after doing all this, it is very likely that there wasn’t any match to begin with.

With this in mind, I created a WinDBG script that does this specifically. It checks if there is any modules with SafeSEH off, and if there is, it will give you a list of addresses pointing to each pop pop ret instruction sequence available, ready to plug-in into your exploit.

The script is the following:

.load narly ; .load soshelp ; r @$t1 = 0 ; r @$t2 = 0 ; .echo "********************************************************************************" ; !sosexec /c "!nmod [0]|SafeSEH OFF"->" r @$t1 = " ; !sosexec /c "!nmod [1]|SafeSEH OFF"->" r @$t2 = " ; .if (@$t1 != 0 & @$t2 != 0) { s-[1]b @$t1 @$t2 58 58 C3 ; s-[1]b @$t1 @$t2 5b 5b C3; s-[1]b @$t1 @$t2 59 59 C3 ; s-[1]b @$t1 @$t2 5a 5a C3 ; s-[1]b @$t1 @$t2 5f 5f C3 ; s-[1]b @$t1 @$t2 5c 5c C3 ; .echo "********************************************************************************" ; .echo "The addresses above point to that instruction sequence." ; .echo "********************************************************************************" ; } .else {.echo "There was no match." ; .echo "********************************************************************************" ; }

It may look like chaos at first, but if you expand it it’s easy to understand what’s happening.

.load narly
.load soshelp
r @$t1 = 0
r @$t2 = 0
.echo "********************************************************************************"
!sosexec /c "!nmod [0]|SafeSEH OFF"->" r @$t1 = "
!sosexec /c "!nmod [1]|SafeSEH OFF"->" r @$t2 = " 
.if (@$t1 != 0 & @$t2 != 0)
s-[1]b @$t1 @$t2 58 58 C3 
s-[1]b @$t1 @$t2 5b 5b C3
s-[1]b @$t1 @$t2 59 59 C3
s-[1]b @$t1 @$t2 5a 5a C3
s-[1]b @$t1 @$t2 5f 5f C3
s-[1]b @$t1 @$t2 5c 5c C3
.echo "********************************************************************************"
.echo "The addresses above point to that instruction sequence."
.echo "********************************************************************************"
.echo "There was no match."
.echo "********************************************************************************"

It begins by loading two important extensions; narly and soshelp. Narly is a WinDBG extension with a single command (!nmod) used to list SafeSEH, GS, DEP, and ASLR information about all loaded modules. Soshelp is a WinDBG extension used for recurse, filter, and pipe commands, which I found very useful in creating this script.

Next, it takes the two pseudo-registers t1 and t2 and initialize them to zero. This is because the script uses these registers to identify wether there is any module with SafeSEH off. If these remain zero, then there isn’t. Because you may want to use this script multiple times during the same session, the scripts starts by resetting these pseudo-registers each time.

All the asterisks are there for formatting and clarity of the output. That’s all .echo “*****” does.

The next two lines take the output of the function “!nmod” and perform an action depending on the result. Specifically, it looks for the data in the first two columns of the output of the function “!nmod”, only from the rows where the string “SafeSEH OFF” is present. Then it assigns the content of this two columns to the pseudo-registers t1 and t2 respectively. If there happens to be no rows with the specified string, then there will be no new value to be assigned to the pseudo-registers, and they both remain zero. To see in more detail how the function “!sosexec” works, refer to http://blogs.msdn.com/b/nicd/archive/2008/12/18/windbg-extension-to-easily-recurse-filter-and-pipe-commands.aspx.

Then, we have an .if statement, which says that the next commands will be executed only if neither t1 or t2 are still zero. This is because if they are still zero, that means there is no module with SafeSEH off, so it will not look for pop pop ret instruction sequences.

The commands inside the .if statement make a simple search for pop pop ret instruction sequences. At this points, t1 and t2 contain the lower and upper bound memory addresses respectively for all the modules with SafeSEH off, so the command “s” use these to restrain its search to relevant modules. Because the only thing useful for us are the addresses pointing to pop pop ret instruction sequences, we use the -[1] flag. This flag makes the output be only the addresses of the matches, instead of all the information about the match, making the output more clean and efficient. The “b” after the flag tells it to search for the instruction sequences in bytes. Finally, the three alphanumeric pairs at the end of each line are the opcodes for the pop pop ret instruction sequences for all different valid pop instructions. That is, “pop esp”, “pop eax”, “pop ebx”, etc.

Once this search is completed, the result will be a list of all the addresses pointing to a pop pop ret instruction sequence inside a module with SafeSEH off, followed by a message saying “The addresses above point to that instruction sequence.”. All the addresses shown here can be plugged-in into your exploit.


If the .if statement fails, it will automatically show a message saying “There was no match.”. This means that there wasn’t a loaded module with SafeSEH off.

That’s it. This script could be useful for any other similar tasks, like bypassing DEP or searching for any other instruction sequence. You’d just have to manually modify the opcodes you’re looking for, and maybe change the filtering string.