memtst.s
.globl _WinMain@16
/*
* .text section
*/
.text
/*
* void vrtqry(void *memaddr,MEMORY_BASIC_INFORMATION *membasicinfoaddr) {
*/
vrtqry:
/*
* A: Standard function prologue to create a stack frame pointer
*/
pushl %ebp
movl %esp,%ebp
/*
* B: Save the registers that either we modify,
* or that _VirtualQuery@12 modifies
*/
pushl %eax
pushl %ecx
pushl %edx
/*
* C: call VirtualQuery(memaddr,membasicinfoaddr)
*/
pushl $0x1c
pushl 0xc(%ebp)
pushl 0x8(%ebp)
call _VirtualQuery@12
/*
* D: Restore the registers
*/
popl %edx
popl %ecx
popl %eax
/*
* E: Standard function epilogue
*/
movl %ebp,%esp
popl %ebp
ret
/*
* }
*/
/*
* F: _WinMain@16()
* Execution begins here
* (we don't care about the arguments)
*/
_WinMain@16:
pushl %ebp
movl %esp,%ebp
/*
* G: Leave space on the stack for a MEMORY_BASIC_INFORMATION
* structure. 0x28 is the structure's size
*/
subl $28,%esp /* sizeof(MEMORY_BASIC_INFORMATION) */
pushl $0x0 /* this is used to indicate second iteration of the loop and terminate it */
/*
* H: Popular malware trick to find the address of the next
* instruction. In this case, the address of the 'popl %eax'
* instruction at nxtinstr.
*/
call nxtinstr
nxtinstr:
/*
* I: pop the return address of the call instruction off the stack
* and in to the eax register. The return address of a call
* instruction is the address of the instruction immediately
* following the call which in this case is the address of the
* following 'popl %eax' instruction, at the address defined by
* the label 'nxtinstr'.
*/
popl %eax
/*
* J: The following 'nop' instruction is a place holder.
* Little does it know that we are going to replace it with an
* 'inc %ebx' instruction. I suspect that if it did, it wouldn't
* be sitting here so calmly.
*/
nop
/*
* K: Call our vryqry() function to get base address and current
* permissions of the memory page containing the 'popl %eax'
* instruction at nxtinstr.
*/
/*
* L: First, push the address of our MEMORY_BASIC_INFORMATION
* structure on the stack.
* This will be the second parameter (they are pushed in reverse
* order) to our vrtqry() function above.
*/
lea -28(%ebp),%edx
pushl %edx /* &MEMORY_BASIC_INFORMATION */
/*
* M: push the return address from the call instruction.
* That is, the address of the instruction at 'nxtinstr', and the
* address for which we are seeking the information.
* This address will be passed as the first argument to our
* vrtqry() function.
*/
pushl %eax
call vrtqry
/*
* N: Remove our arguments from the stack, as our vrtqry()
* function doesn't
*/
addl $0x8,%esp
/*
* O: Save the registers modified by printf()
*/
pushl %eax
pushl %edx /* changed by printf() */
/*
* P: Print out some of the fields from the
* MEMORY_BASIC_INFORMATION structure.
* call printf("BaseAddress: 0x%x\nAllocationBase: 0x%x\nAllocationProtect: 0x%x\nProtect: 0x%x\nType: 0x%x\n",BaseAddress,AllocationBase,State,Protect,Type)
*/
addl $0x18,%edx /* &MEMORY_BASIC_INFORMATION.Type */
pushl (%edx)
subl $0x4,%edx /* &MEMORY_BASIC_INFORMATION.Protect */
pushl (%edx)
subl $0x4,%edx /* &MEMORY_BASIC_INFORMATION.State */
pushl (%edx)
subl $0xc,%edx /* &MEMORY_BASIC_INFORMATION.AllocationBase */
pushl (%edx)
subl $0x4,%edx /* &MEMORY_BASIC_INFORMATION.BaseAddress */
pushl (%edx)
pushl $fmt_vrtqry /* address of format string */
call _printf
addl $0x18,%esp /* Remove arguments from the stack */
/*
* Q: Restore registers
*/
popl %edx
popl %eax
/*
* R: Call _VirtualProtect@16() to modify the page permissions by
* adding WRITE
* %edx points to start of MEMORY_BASIC_INFORMATION structure
* .Protect needs to change from 0x20 (PAGE_EXECUTE_READ) to
* 0x40 (PAGE_EXECUTE_READWRITE)
*/
// pushl %eax /* save value of eax register */
// subl $0x4,%esp /* leave space on stack for lpflOldProtect */
// pushl %esp /* addr of lpflOldProtect */
// pushl $0x40 /* flNewProtect */
// pushl $0x0fff /* dwSize */
// pushl (%edx) /* lpAddress */
// call _VirtualProtect@16
/*
* S: call printf() to print value returned from VirtualProtect()
* and flOldProtect
*/
/* old flProtect will be on stack */
// pushl %eax /* BOOL value returned from VirtualProtect() */
// pushl $fmt_result
// call _printf
// addl $0xc,%esp
// popl %eax /* restore value of eax register */
/*
* T: Call getchar() to pause the process
* to allow a kernel debugger to be attached
*/
pushl %eax
call _getchar
popl %eax
pushl %eax /* save eax register as printf() returns number of characters printed in eax, which will clobber it */
/*
* U: call printf() to print address in eax register
* and the contents of the ebx register
*/
pushl %ebx
pushl %eax
pushl $fmtstr2
call _printf
addl $0xc,%esp
popl %eax /* restore eax register */
/*
* V: Check the contents of the eax register
* On the first iteration, this will be the address of the 'popl
* %eax' instruction at nxtinstr:
* On the second iteration, this will be the 0 that we push on to
* the stack near the start of _WinMain@16()
*/
cmpl $0x0,%eax
je skiprpt
/*
* W: If eax is not zero, then modify the 'nop' instruction to
* 'inc %ebx' and loop back to the address in eax.
*/
/* Sit tight -- this may hurt a little */
movb $0x43,0x1(%eax)
/* X: jump back to nxtinstr: */
jmp *%eax
skiprpt:
/* Y: return 0 */
xor %eax,%eax
leave
ret
/*
* Z: .data section
*/
.data
fmtstr: .ascii "%d\n"
fmtstr2: .ascii "nop is at 0x%x\n%%ebx: 0x%x\n"
fmt_vrtqry: .ascii "BaseAddress: 0x%x\nAllocationBase: 0x%x\nAllocationProtect: 0x%x\nProtect: 0x%x\nType: 0x%x\n"
fmt_result: .ascii "Returned: %d\nflOldProtect: 0x%x\n"