Assembly Saving Flags / Registers (More SLAE “Fun”)

Another week, and another post about my SLAE progress! This time, I’ll be covering assembly saving flags and registers.

Assembly Saving Flags – Introduction

While the opcodes to save flags and registers are fairly simple, this is the third program (after “Hello World” and multiplication/division) that I wrote on my own for SLAE.

I’m sure you all are getting tired of my code posts that aren’t really tutorials, but I’m getting closer to being ready for the SLAE exam at least!

For this exercise, I had to write a program that performed the following actions.

  • Write a program which saves registers and flags before calling a procedure
  • It should also save/restore the frame pointer

The Code

The code is pretty similar to my “Hello World” application, so I will only cover the differences.

First, I have added a hello world procedure that will actually do the printing of my “message” to the screen. This code is exactly the same as my previous application, with two additions. These additions are a function prologue (enter 0, 0) and epilogue (leave; ret).

The function prologue functions similarly to a (push ebp; mov ebp, esp; sub esp 0). This performs the first half of the second requirement, which is saving the frame pointer. The function epilogue is functionally similar to (mov esp, ebp; pop ebp; ret). Similarly to the function prologue, this restores the same frame pointer from the beginning of the procedure.

With the second requirement covered, let’s move on to the _start label. In this case, it only contains a (mov ecx, 0x5). This will be a counter for the number of times we will loop. In this case, the program will print “Hello World!” 5 times, and this also serves as an example for saving a register (requirement #1).

The PrintHelloWorld section is a bit different as well. First up, we have the pushad and pushfd instructions. These fulfill the first half of the first requirement, which is saving the registers and flags before calling the procedure. Pushad/pushfd push the contents of the general purpose registers and flags (respectively) onto the stack, and adjust the stack pointer accordingly. After the call to HelloWorldProc, the program will execute the popad and popfd instructions, which reset the registers and flags to their original values.

With both requirements met, the procedure loops, and then cleanly exits.

The full code for this example is found below.

; Filename: HelloWorldSaveState.nasm
; Author: Ray Doyle
; Reference: https://en.wikipedia.org/wiki/Function_prologue

global _start            

section .text
HelloWorldProc:
    enter 0, 0

    ; Print hello world using write syscall
    mov eax, 0x4
    mov ebx, 0x1
    mov ecx, message
    mov edx, mlen
    int 0x80

    leave
    ret

_start:
    mov ecx, 0x5

PrintHelloWorld:
    ; preserve registers and flags     
    pushad
    pushfd

    call HelloWorldProc

    ; restore registers and stack
    popfd
    popad

    loop PrintHelloWorld

    mov eax, 1
    mov ebx, 10        ; sys_exit syscall
    int 0x80

section .data

    message: db "Hello World!"
    mlen     equ $-message

Tracing Execution

Before tracing the execution, it is important to test that the program actually works. As expected, the program prints “Hello World!” five times before exiting.

doyler@slae:~/slae/module1-10$ vi HelloWorldSaveState.nasm
doyler@slae:~/slae/module1-10$ sh ../compile.sh HelloWorldSaveState
[+] Assembling with Nasm ...
[+] Linking ...
[+] Done!
doyler@slae:~/slae/module1-10$ ls
HelloWorldSaveState  HelloWorldSaveState.nasm  HelloWorldSaveState.o
doyler@slae:~/slae/module1-10$ ./HelloWorldSaveState
Hello World!Hello World!Hello World!Hello World!Hello World!

With the program verified as working, it was time for me to trace the execution. I’ve cut out most of the loop, but the general program flow still holds true:

  1. Start the program
  2. Setup the loop counter
  3. Preserve the registers and flags
  4. Preserve the stack pointer
  5. Print “Hello World!” to the screen
  6. Restore the stack pointer
  7. Restore the registers and flags
  8. Loop x5
  9. Cleanly exit
doyler@slae:~/slae/module1-10$ gdb -q HelloWorldSaveState
Reading symbols from /home/doyler/slae/module1-10/HelloWorldSaveState...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) break _start
Breakpoint 1 at 0x804809c
(gdb) define hook-stop
Type commands for definition of "hook-stop".
End with a line saying just "end".
>print/x $eax
>print/x $ebx
>print/x $ecx
>print/x $edx
>print/x $ebp
>x/xw &message
>x/4xw $esp
>disassemble $eip,+10
>end
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/doyler/slae/module1-10/HelloWorldSaveState
$22 = 0x0
$23 = 0x0
$24 = 0x0
$25 = 0x0
$26 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3d0:    0x00000001    0xbffff53a    0x00000000    0xbffff56b
Dump of assembler code from 0x804809c to 0x80480a6:
=> 0x0804809c <_start+0>:    mov    ecx,0x5
   0x080480a1 <PrintHelloWorld+0>:    pusha  
   0x080480a2 <PrintHelloWorld+1>:    pushf  
   0x080480a3 <PrintHelloWorld+2>:    call   0x8048080 <HelloWorldProc>
End of assembler dump.

Breakpoint 1, 0x0804809c in _start ()
(gdb) nexti
$27 = 0x0
$28 = 0x0
$29 = 0x5
$30 = 0x0
$31 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3d0:    0x00000001    0xbffff53a    0x00000000    0xbffff56b
Dump of assembler code from 0x80480a1 to 0x80480ab:
=> 0x080480a1 <PrintHelloWorld+0>:    pusha  
   0x080480a2 <PrintHelloWorld+1>:    pushf  
   0x080480a3 <PrintHelloWorld+2>:    call   0x8048080 <HelloWorldProc>
   0x080480a8 <PrintHelloWorld+7>:    popf   
   0x080480a9 <PrintHelloWorld+8>:    popa   
   0x080480aa <PrintHelloWorld+9>:    loop   0x80480a1 <PrintHelloWorld>
End of assembler dump.
0x080480a1 in PrintHelloWorld ()
(gdb) nexti
$32 = 0x0
$33 = 0x0
$34 = 0x5
$35 = 0x0
$36 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3b0:    0x00000000    0x00000000    0x00000000    0xbffff3d0
Dump of assembler code from 0x80480a2 to 0x80480ac:
=> 0x080480a2 <PrintHelloWorld+1>:    pushf  
   0x080480a3 <PrintHelloWorld+2>:    call   0x8048080 <HelloWorldProc>
   0x080480a8 <PrintHelloWorld+7>:    popf   
   0x080480a9 <PrintHelloWorld+8>:    popa   
   0x080480aa <PrintHelloWorld+9>:    loop   0x80480a1 <PrintHelloWorld>
End of assembler dump.
0x080480a2 in PrintHelloWorld ()
(gdb) print $eflags
$37 = [ IF ]
(gdb) nexti
$38 = 0x0
$39 = 0x0
$40 = 0x5
$41 = 0x0
$42 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3ac:    0x00000302    0x00000000    0x00000000    0x00000000
Dump of assembler code from 0x80480a3 to 0x80480ad:
=> 0x080480a3 <PrintHelloWorld+2>:    call   0x8048080 <HelloWorldProc>
   0x080480a8 <PrintHelloWorld+7>:    popf   
   0x080480a9 <PrintHelloWorld+8>:    popa   
   0x080480aa <PrintHelloWorld+9>:    loop   0x80480a1 <PrintHelloWorld>
   0x080480ac <PrintHelloWorld+11>:    mov    eax,0x1
End of assembler dump.
0x080480a3 in PrintHelloWorld ()
(gdb) nexti
$43 = 0x0
$44 = 0x0
$45 = 0x5
$46 = 0x0
$47 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3a8:    0x080480a8    0x00000302    0x00000000    0x00000000
Dump of assembler code from 0x8048080 to 0x804808a:
=> 0x08048080 <HelloWorldProc+0>:    enter  0x0,0x0
   0x08048084 <HelloWorldProc+4>:    mov    eax,0x4
   0x08048089 <HelloWorldProc+9>:    mov    ebx,0x1
End of assembler dump.
0x08048080 in HelloWorldProc ()
(gdb) nexti
$48 = 0x0
$49 = 0x0
$50 = 0x5
$51 = 0x0
$52 = 0xbffff3a4
0x80490b8 <message>:    0x6c6c6548
0xbffff3a4:    0x00000000    0x080480a8    0x00000302    0x00000000
Dump of assembler code from 0x8048084 to 0x804808e:
=> 0x08048084 <HelloWorldProc+4>:    mov    eax,0x4
   0x08048089 <HelloWorldProc+9>:    mov    ebx,0x1
End of assembler dump.
0x08048084 in HelloWorldProc ()
(gdb) nexti
$53 = 0x4
$54 = 0x0
$55 = 0x5
$56 = 0x0
$57 = 0xbffff3a4
0x80490b8 <message>:    0x6c6c6548
0xbffff3a4:    0x00000000    0x080480a8    0x00000302    0x00000000
Dump of assembler code from 0x8048089 to 0x8048093:
=> 0x08048089 <HelloWorldProc+9>:    mov    ebx,0x1
   0x0804808e <HelloWorldProc+14>:    mov    ecx,0x80490b8
End of assembler dump.
0x08048089 in HelloWorldProc ()
(gdb) nexti
$58 = 0x4
$59 = 0x1
$60 = 0x5
$61 = 0x0
$62 = 0xbffff3a4
0x80490b8 <message>:    0x6c6c6548
0xbffff3a4:    0x00000000    0x080480a8    0x00000302    0x00000000
Dump of assembler code from 0x804808e to 0x8048098:
=> 0x0804808e <HelloWorldProc+14>:    mov    ecx,0x80490b8
   0x08048093 <HelloWorldProc+19>:    mov    edx,0xc
End of assembler dump.
0x0804808e in HelloWorldProc ()
(gdb) nexti
$63 = 0x4
$64 = 0x1
$65 = 0x80490b8
$66 = 0x0
$67 = 0xbffff3a4
0x80490b8 <message>:    0x6c6c6548
0xbffff3a4:    0x00000000    0x080480a8    0x00000302    0x00000000
Dump of assembler code from 0x8048093 to 0x804809d:
=> 0x08048093 <HelloWorldProc+19>:    mov    edx,0xc
   0x08048098 <HelloWorldProc+24>:    int    0x80
   0x0804809a <HelloWorldProc+26>:    leave  
   0x0804809b <HelloWorldProc+27>:    ret    
   0x0804809c <_start+0>:    mov    ecx,0x5
End of assembler dump.
0x08048093 in HelloWorldProc ()
(gdb) nexti
$68 = 0x4
$69 = 0x1
$70 = 0x80490b8
$71 = 0xc
$72 = 0xbffff3a4
0x80490b8 <message>:    0x6c6c6548
0xbffff3a4:    0x00000000    0x080480a8    0x00000302    0x00000000
Dump of assembler code from 0x8048098 to 0x80480a2:
=> 0x08048098 <HelloWorldProc+24>:    int    0x80
   0x0804809a <HelloWorldProc+26>:    leave  
   0x0804809b <HelloWorldProc+27>:    ret    
   0x0804809c <_start+0>:    mov    ecx,0x5
   0x080480a1 <PrintHelloWorld+0>:    pusha  
End of assembler dump.
0x08048098 in HelloWorldProc ()
(gdb) nexti
Hello World!$73 = 0xc
$74 = 0x1
$75 = 0x80490b8
$76 = 0xc
$77 = 0xbffff3a4
0x80490b8 <message>:    0x6c6c6548
0xbffff3a4:    0x00000000    0x080480a8    0x00000302    0x00000000
Dump of assembler code from 0x804809a to 0x80480a4:
=> 0x0804809a <HelloWorldProc+26>:    leave  
   0x0804809b <HelloWorldProc+27>:    ret    
   0x0804809c <_start+0>:    mov    ecx,0x5
   0x080480a1 <PrintHelloWorld+0>:    pusha  
   0x080480a2 <PrintHelloWorld+1>:    pushf  
   0x080480a3 <PrintHelloWorld+2>:    call   0x8048080 <HelloWorldProc>
End of assembler dump.
0x0804809a in HelloWorldProc ()
(gdb) nexti
$78 = 0xc
$79 = 0x1
$80 = 0x80490b8
$81 = 0xc
$82 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3a8:    0x080480a8    0x00000302    0x00000000    0x00000000
Dump of assembler code from 0x804809b to 0x80480a5:
=> 0x0804809b <HelloWorldProc+27>:    ret    
   0x0804809c <_start+0>:    mov    ecx,0x5
   0x080480a1 <PrintHelloWorld+0>:    pusha  
   0x080480a2 <PrintHelloWorld+1>:    pushf  
   0x080480a3 <PrintHelloWorld+2>:    call   0x8048080 <HelloWorldProc>
End of assembler dump.
0x0804809b in HelloWorldProc ()
(gdb) nexti
$83 = 0xc
$84 = 0x1
$85 = 0x80490b8
$86 = 0xc
$87 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3ac:    0x00000302    0x00000000    0x00000000    0x00000000
Dump of assembler code from 0x80480a8 to 0x80480b2:
=> 0x080480a8 <PrintHelloWorld+7>:    popf   
   0x080480a9 <PrintHelloWorld+8>:    popa   
   0x080480aa <PrintHelloWorld+9>:    loop   0x80480a1 <PrintHelloWorld>
   0x080480ac <PrintHelloWorld+11>:    mov    eax,0x1
   0x080480b1 <PrintHelloWorld+16>:    mov    ebx,0xa
End of assembler dump.
0x080480a8 in PrintHelloWorld ()
(gdb) nexti
$88 = 0xc
$89 = 0x1
$90 = 0x80490b8
$91 = 0xc
$92 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3b0:    0x00000000    0x00000000    0x00000000    0xbffff3d0
Dump of assembler code from 0x80480a9 to 0x80480b3:
=> 0x080480a9 <PrintHelloWorld+8>:    popa   
   0x080480aa <PrintHelloWorld+9>:    loop   0x80480a1 <PrintHelloWorld>
   0x080480ac <PrintHelloWorld+11>:    mov    eax,0x1
   0x080480b1 <PrintHelloWorld+16>:    mov    ebx,0xa
End of assembler dump.
0x080480a9 in PrintHelloWorld ()
(gdb) print $eflags
$93 = [ TF IF ]
(gdb) nexti
$94 = 0x0
$95 = 0x0
$96 = 0x5
$97 = 0x0
$98 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3d0:    0x00000001    0xbffff53a    0x00000000    0xbffff56b
Dump of assembler code from 0x80480aa to 0x80480b4:
=> 0x080480aa <PrintHelloWorld+9>:    loop   0x80480a1 <PrintHelloWorld>
   0x080480ac <PrintHelloWorld+11>:    mov    eax,0x1
   0x080480b1 <PrintHelloWorld+16>:    mov    ebx,0xa
End of assembler dump.
0x080480aa in PrintHelloWorld ()

...

(gdb) nexti
$379 = 0x0
$380 = 0x0
$381 = 0x0
$382 = 0x0
$383 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3d0:    0x00000001    0xbffff53a    0x00000000    0xbffff56b
Dump of assembler code from 0x80480ac to 0x80480b6:
=> 0x080480ac <PrintHelloWorld+11>:    mov    eax,0x1
   0x080480b1 <PrintHelloWorld+16>:    mov    ebx,0xa
End of assembler dump.
0x080480ac in PrintHelloWorld ()
(gdb) nexti
$384 = 0x1
$385 = 0x0
$386 = 0x0
$387 = 0x0
$388 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3d0:    0x00000001    0xbffff53a    0x00000000    0xbffff56b
Dump of assembler code from 0x80480b1 to 0x80480bb:
=> 0x080480b1 <PrintHelloWorld+16>:    mov    ebx,0xa
   0x080480b6 <PrintHelloWorld+21>:    int    0x80
   0x080480b8:    dec    eax
   0x080480b9:    gs
   0x080480ba:    ins    BYTE PTR es:[edi],dx
End of assembler dump.
0x080480b1 in PrintHelloWorld ()
(gdb) nexti
$389 = 0x1
$390 = 0xa
$391 = 0x0
$392 = 0x0
$393 = 0x0
0x80490b8 <message>:    0x6c6c6548
0xbffff3d0:    0x00000001    0xbffff53a    0x00000000    0xbffff56b
Dump of assembler code from 0x80480b6 to 0x80480c0:
=> 0x080480b6 <PrintHelloWorld+21>:    int    0x80
   0x080480b8:    dec    eax
   0x080480b9:    gs
   0x080480ba:    ins    BYTE PTR es:[edi],dx
   0x080480bb:    ins    BYTE PTR es:[edi],dx
   0x080480bc:    outs   dx,DWORD PTR ds:[esi]
   0x080480bd:    and    BYTE PTR [edi+0x6f],dl
End of assembler dump.
0x080480b6 in PrintHelloWorld ()
(gdb) nexti
[Inferior 1 (process 23862) exited with code 012]
Error while running hook_stop:
No registers.

Assembly Saving Flags – Conclusion

While this was another fairly simple assembly program, it was one that I wrote on my own before the course demonstrated it to me.

The Intel instruction set manual is a great reference, and I see myself returning it to it plenty in the future.

There will be a large amount of assembly posts to come, but I will do my best to mix in some other topics here and there. If you do not like the formatting or style of these posts, then please let me know if you have any suggestions. I was hoping to include a bit of the GDB tracing to make it easier to follow, but it can definitely be a huge wall of text.

doyler on Githubdoyler on Twitter
doyler
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he's done it all. To show for it, he has obtained an OSCP, eCPPT, eWPT, eWPTX, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!

He currently serves as a Senior Penetration Testing Consultant for Secureworks. His previous position was a Senior Penetration Tester for a major financial institution.

When he's not figuring out what cert to get next (currently GXPN) or side project to work on, he enjoys playing video games, traveling, and watching sports.

Leave a Comment

Filed under Security Not Included

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.