Problem: I'm working on a project for school (my choice) which is a program loader/DLL injector, the idea of which I initially found here, modified to suit my needs, and converted the ASM portions of the DLL to extended ASM that will compile with GCC instead of Visual Studio. Rather than do the pinball score print in a console window thing, I'm loading a program I wrote that takes input from a user and writes it to a file. The loader injects a DLL with a function in it that redirects user input, formerly destined for a file, to a messagebox, and will write my own string to the file.
It works on my machine, however, I have concerns about platform switching because my professor has to compile the work on her machine, so it is possible that the address 0x004014A6, which currently contains the instruction to
CALL <some address>
which writes that string to a file(the actual code is: ofile << user_input;
) won't conta开发者_运维问答in anything close to that when compiled on another machine, but will still have a call to that function that writes a string to a file.
What I want to do is dynamically determine what that address will be, as opposed to hardcoding the address. I think I can do this by using GetProcAddress on the function that gets called to get the address, then create an array to hold the bytes representing CALL <that function>
, and search byte by byte in memory somewhere around where I expect to find that call to be made, take the address, and work from there.
I don't know exactly how to do that, though.
MAIN QUESTION: How can I scan a range of memory addresses and compare the contents to elements of an array?
Put another way, I want to include in my DLL a function that reads bytes at an arbitrary address in memory and compares it to an expected sequence. How can I just arbitrarily read contents of memory addresses within a certain process?
Suspicions: I'll need to know the starting and ending addresses where execution of the original program takes place. How can I get the range between starting and ending addresses? (This seems like the real hurdle here. I can probably get the rest knowing only how to obtain the processes beginning and ending addresses.)
Unless the version of the program is your targeting is gonna change soon, you can use VA(virtual address) = RVA(relative virtual address) + module Base load address(which can be gotten with GetModuleHandle
) to get an address that won't fail under different systems. If the version does change, then your looking at a signature scanner. They aren't foolproof however, as the patterns your scanning for can radically change from one build to the next. Any range data needed can be gotten from the PE of the targetted app, that can then be used to temporarily apply read privilages to the .code
section, allowing you to loop through it efficiently(the not so efficient was is to use ReadProcessMemory
). Here is a small sigscanner lib, farther down is also a link to source for a simple sig scanner: http://www.blizzhackers.cc/viewtopic.php?f=182&t=478228&sid=55fc9a949aa0beb2ca2fb09e933210de
If you are using Python, maybe ptrace could help. It is cross-platfrom, and could be installed from pip. Here's a code snip for unix that I grabbed here: http://sixserv.org/2010/07/26/memory-debugging-or-a-universal-game-trainer-with-python-and-ptrace/
def search_memory_locations(pid, max_memory, search_value):
child_pid = os.fork()
if child_pid == 0: # search within forked process:
locations = list()
prev_locations = read_locations()
dbg = PtraceDebugger()
process = dbg.addProcess(pid, False)
memory_mappings = readProcessMappings(process)
print "\x1B[?25l", # deactivate cursor (^_^)
for memory_mapping in memory_mappings:
# only search in read/writable memory areas within range...
if "rw" in memory_mapping.permissions and memory_mapping.end <= max_memory:
for loc in range(memory_mapping.start, memory_mapping.end):
value = process.readBytes(loc, 1)
if value[0] == search_value:
print "search memory area[0x%08X-0x%08X] address[0x%08X] value[0x%02X (%03d)] \r" % (memory_mapping.start, memory_mapping.end, loc, ord(value), ord(value)),
if prev_locations and len(prev_locations) > 0 and not loc in prev_locations:
continue # skip prev not found locations
locations.append(loc)
print "\x1B[?25h", # activate cursor
dbg.quit()
write_locations(locations)
sys.exit()
return child_pid # don't really need this
If you are using C/C++, here's a function specific for Windows that I used before from ITH (http://code.google.com/p/interactive-text-hooker/):
DWORD SearchPattern(DWORD base, DWORD base_length, LPVOID search, DWORD search_length) //KMP
{
__asm
{
mov eax,search_length
alloc:
push 0
sub eax,1
jnz alloc
mov edi,search
mov edx,search_length
mov ecx,1
xor esi,esi
build_table:
mov al,byte ptr [edi+esi]
cmp al,byte ptr [edi+ecx]
sete al
test esi,esi
jz pre
test al,al
jnz pre
mov esi,[esp+esi*4-4]
jmp build_table
pre:
test al,al
jz write_table
inc esi
write_table:
mov [esp+ecx*4],esi
inc ecx
cmp ecx,edx
jb build_table
mov esi,base
xor edx,edx
mov ecx,edx
matcher:
mov al,byte ptr [edi+ecx]
cmp al,byte ptr [esi+edx]
sete al
test ecx,ecx
jz match
test al,al
jnz match
mov ecx, [esp+ecx*4-4]
jmp matcher
match:
test al,al
jz pre2
inc ecx
cmp ecx,search_length
je finish
pre2:
inc edx
cmp edx,base_length //search_length
jb matcher
mov edx,search_length
dec edx
finish:
mov ecx,search_length
sub edx,ecx
lea eax,[edx+1]
lea ecx,[ecx*4]
add esp,ecx
}
}
精彩评论