; #########################################################################
;
;   SMC.ASM is a test piece for reading and writing to the code section
;   of a PE file. In this example, there are two procedures, one which
;   is called, the second that is read and written at the address
;   of the first. The proc is called twice, before & after the code has
;   been modified.
;
;   This is made possible by using the link option "/section:.text,RWE"
;   which sets the code section as read/write/execute. This file should
;   be built with the supplied "build.bat"
;
;   Iczelion assisted in the development of this example.
;
; #########################################################################

      .386
      .model flat, stdcall
      option casemap :none   ; case sensitive

; #########################################################################

      include \masm32\include\windows.inc
      include \masm32\include\user32.inc
      include \masm32\include\kernel32.inc

      includelib \masm32\lib\user32.lib
      includelib \masm32\lib\kernel32.lib

      CalledProc PROTO
      ReplaceMentProc  PROTO

; #########################################################################

    .data
        lnth1       dd 0
        szDlgTitle  db "SMC example",0
        Phony       db "This is 1st call of proc",0
        Replc       db "This is 2nd call of proc",0
        ttl1        db "Original Code",0
        ttl2        db "Replacement Code",0

; #########################################################################
    
    .code

start:

    invoke CalledProc   ; call proc as written
    
    lea eax, rpEnd      ; end label of 2nd proc
    lea edx, rpStart    ; start label of 2nd proc
    sub eax, edx        ; get offset differences
    mov lnth1, eax      ; save the length

    lea esi, rpStart    ; load address of 2nd proc
    lea edi, ppStart    ; load address of 1st proc
    mov ecx, lnth1      ; put length of 2nd proc in ecx
    rep movsb           ; write code from 2nd proc to address of 1st

    invoke CalledProc   ; call it again after it has been modified

    invoke ExitProcess,0

; #########################################################################

CalledProc proc

    ppStart::   ; labels with [ :: ] are visable GLOBALLY.

    invoke MessageBox,0,ADDR Phony,ADDR ttl1,MB_OK

    ppEnd::

  ; ------------------------------------------------------
  ; The "nop's" are padding to ensure that there is enough
  ; room for the code that is written between the 2 labels
  ; ------------------------------------------------------

    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop

    ret

CalledProc endp

; #########################################################################

ReplaceMentProc proc

    ; -----------------------------------
    ; this proc is never called but the
    ; code between the two labels is read
    ; and then written to the address of
    ; the first proc
    ; -----------------------------------

    rpStart::
    
    push MB_OK or MB_ICONEXCLAMATION
    lea eax, ttl2
    push eax
    lea eax, Replc
    push eax
    push 0
    lea eax, MessageBox
    call eax

    rpEnd::

    ret

ReplaceMentProc endp

; #########################################################################

end start