Unlike exe's, dll's do not always get loaded into the same address space (i.e. 00400000). This address is called the 'Base Address' and is a pointer to the "M" in the "MZ" signature (which is if you dont know, is the first two bytes in any portable executable [i.e. exe's and dll's, any some other files]).
If when we are memory editing an executable and the address we wish to change is 400123, it will always be 400123. HOWEVER, if the address we wish to modify resides inside a DLL loaded by a process, the chances of that dll being loaded into the same location in memory everytime that process runs or calls the DLL is slim to none.
So, to get the address in a usable form we must subtract the image base from the desired address. If for example, the address we wanted to patch in a dll was 10001099, and the ImageBase of that DLL was 10001000, we would simply subtract the ImageBase from the Relative Address.
e.g. 10001099h (wanted address) - 10001000h (ImageBase) = 99h
This is handy because now we can enumerate through all loaded dlls on your system (using toolhelp api) for the one we are after, then retrieve the base address of this dll and subsequently add our computed value (in this case 99h) to the ImageBase. And this will now give us a perfectly valid and usable address to write to memory with using WriteProcessMemory.
Enough ranting, here's the code. (The code is in
NB: szCLASS is a pointer to a string holding the class name of the process we want to mess with and that has loaded the dll. I havn't included all the source, only the main snippets, such as my GetModuleBaseAddress function and some of the code that calls this. GetModuleBaseAddress takes two parameters, the first which is the ProcessID of the target process (retrieved from OpenProcess) and secondly, a string to the dll we are searching for. If the function suceeds it will return the base address of the chosen dll, if it failed, eax will return 0.
After this call, you would see a very basic instruction "add eax, 1440hh". This is the value I calculated using the method as described earlier on. As you notice in the WPM() call, in the address parameter it has EAX, which is the address of the ImageBase PLUS the pointer value (in my case it was 14408h).
Viola! That's it. As you have seen it's a bit harder than writing to a exe, but overall, not too difficult. None of the code here is specific to asm and can be ported to any language with relative ease. Hopefully someone finds this useful!
Invoke FindWindow, ADDR szCLASS, 0
Invoke GetWindowThreadProcessId, eax, addr ProcessID
Invoke OpenProcess, PROCESS_VM_READ + PROCESS_VM_WRITE + PROCESS_VM_OPERATION, 0, ProcessID
mov ebx, eax
Invoke GetModuleBaseAddress, ProcessID, ADDR szDLL
add eax, 14408h
invoke WriteProcessMemory, ebx, eax, ADDR bytes, 6, NULL
invoke CloseHandle, ebx
GetModuleBaseAddress proc iProcID:DWORD, DLLName:DWORD
LOCAL hSnap:DWORD
LOCAL xModule:MODULEENTRY32
invoke CreateToolhelp32Snapshot, TH32CS_SNAPMODULE, iProcID
mov hSnap,eax
mov xModule.dwSize, sizeof xModule
invoke Module32First, hSnap, addr xModule
test eax, eax
jnz @getdll
mov eax, 0
ret
@getdll:
invoke Module32Next, hSnap, addr xModule
test eax, eax
jnz @checkdll
mov eax, 0
ret
@checkdll:
invoke lstrcmpi, DLLName, addr xModule.szModule
test eax, eax
jnz @getdll
mov eax, xModule.modBaseAddr
ret
GetModuleBaseAddress endp

