Helloes again.

I'm currently undergoing a game modding process, and for anyone familiar with Cave Story and its tribute site, I'm making my own Legacy mod here.

Yes, in all actuality this can be considered h@cking or reverse-engineering... The difference is, I have Pixel's permission! If you want proof, you can see his bbc here.
You'll have to scroll down a bit, but it's there. Yes, I know most of it's in Japanese, but I ask Pixel in English and he replies in English. I went by my username here when I asked him.

At any rate, I'm trying to get the executable to use PxTone.dll to play music files that I've created. I'm using the PEBrowse Professional Interactive debugger to look at its dissassembly, if that's any use to anyone. I'm using a disassembler because Pixel's reluctant to release the source code.

I'm assuming that once the DLL is loaded, you simply call the hex address of whichever function you want to use, with all the variables and stuff in the stack and registers.

This may be a relatively simple question to answer, but I tried searching and I didn't find anything specific to what I'm trying to do. Once I figure out what to do, I plan on assembling my code pieces in FASM and using XVI32 to insert them into the executable, though I'm not sure how well that will work... I'm pretty sure that if I did that I would have to adjust all the jump offsets and stuff, which might take me a few years, if not decades or centuries...

But you're the experts, you tell me!

- keantoken
Posted on 2007-11-15 00:19:14 by keantoken
LoadLibrary -> GetProcAddress (to get the api's you need)
before exiting do a FreeLibrary on the libraries / library loaded
(not really needed tho)...
Posted on 2007-11-15 01:44:31 by evlncrn8
Hm, not really sure what to do about this topic - seems you have permission and you're not doing malicious stuff, but it is still somewhat touchy. I'll start by moving it to "Low Level Concepts".

Anyway, instead of adding your code to the executable etc., you should consider taking "the easy route". Put the code you want to add in a DLL, and make a loader that injects this DLL. You can do code fixups from the DLL, etc. It's the approach I used for fixing UFO/XCOM, and it works pretty well.
Posted on 2007-11-16 07:29:04 by f0dder
Hm, not really sure what to do about this topic - seems you have permission and you're not doing malicious stuff, but it is still somewhat touchy. I'll start by moving it to "Low Level Concepts".


Don't worry, you can trust me. I respect Pixel enough not to just start h@cking his stuff -  he was able to create such a great game by himself in a matter of five years. I would think that that takes determintion at the very least. That said, I would not even think about doing anything illegal with his code.

At any rate, thanks for the advice.

Do you think I could use your XCOM source as a base for my own project? If so, what assembler did you use?

- keantoken
Posted on 2007-11-16 17:45:27 by keantoken
Sure, knock yourself out. Can't remember which assembler I used, probably MASM back then. With the DLL approach, you can write code in whatever language you want :)
Posted on 2007-11-16 18:04:34 by f0dder
Thanks!

Okay, I pretty much just messed around a bit in FASM, compiling and fixing any errors it found (I haven't completely memorized all the formatting and stuff, and it was faster than searching through the manual) and managed to get it to compile. Of course, that doesn't always mean it compiled RIGHT. At any rate, here's the converted file:

include "WIN32A.INC"

;
; Patch code for 9x,nt,2k,xp.
;
;XCOM: UFO defense (aka  UFO: Enemy Unknown) windows version loader, by f0dder.
;That's f0dder@druk.nu , http://f0dder.has it , http://f0dder.cjb.net
;All rights desrever ;), 2003/04/30.
;
; This code will be written at the program entrypoint. It's job is to load the
; patch DLL file, GetProcAddress, and signal to the patcher that it's done.
; Loader is responsible for register preservation etc.
;



;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; code
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__entry:
        jmp                    short  skipdata

        ; imports fixed by loader
        hEvent                          dd      0
        _LoadLibraryA          dd      0
        _GetProcAddressA        dd      0
        _SetEvent                      dd      0

skipdata:
        ; get delta
        call            .getdelta
.getdelta:
        pop                    ebp
        sub                    ebp, .getdelta

        ; load the DLL
        lea                    eax,
        stdcall        , eax
        ; get address of the doPatch routine
        lea                    edx,
        stdcall        , eax, edx
        call            eax

        ; signal we're done to the loader
        stdcall        , dword

.infiniteloop:
        jmp                    $                                      ; we're done.

szDllName      db "patch.dll", 0
szProcName      db "DoPatch", 0
                                                                                                                                                           


First of all, this may not be the last time I mod a file this way, so I would like to add some flexibility to it. I want it to it's own filename so that it will load the DLLs into an executable in the same folder with the same name. I imagine that this would be done with a syscall like 'GetFileName'. Looking into it...

EDIT: I found GetFileTitle pretty quickly in VisAsm...


        push {cbBuf}                    ; length of buffe
        push {lpszTitle}                ; address of buffer that receives filenam
        push {lpszFile}                  ; address of full path and filename for fil
        call GetFileTitle


Don't ask me why the comments are cut off. Probably a bug with VisAsm. My question is... Ah, I think I just found the answer! It's really nice how you can just type in the syscall on google and it'll give you the NSDN documentation on it. If I'm not mistaken, the buffers it's talking about are the exact same type as the 'szDllName      db "patch.dll", 0' in the previous code snippet. Well, that clears some stuff up.

At any rate, this doesn't seem to be what I want...

- keantoken
Posted on 2007-11-16 18:51:26 by keantoken
if you can explain in more detail what you require i can probably help you...
Posted on 2008-01-01 20:35:27 by evlncrn8
Best way to do this will be with an injector as stated in a previous post.

You will want to make your injector start the game and then inject your dll, then quit. Here is a general template broken into 3 files that you will be able to modify, originally for Starcraft:Broodwar.

.Data
BWFXN_PrintText dd 0048CE70h

.Data?
lgJmp db 5 dup(?)

.Code

BWTextDisplay proc uses ecx edx text:DWORD

xor edx, edx
mov ecx, text
call dword ptr
ret

BWTextDisplay endp

WriteMem proc MemOffset:DWORD, DataPtr:DWORD, dataLen:DWORD

LOCAL OldProt:DWORD

invoke VirtualProtect, MemOffset, dataLen, PAGE_EXECUTE_READWRITE, addr OldProt
invoke RtlMoveMemory, MemOffset, DataPtr, dataLen
invoke VirtualProtect, MemOffset, dataLen, OldProt, addr OldProt
ret

WriteMem endp

JmpPatch proc uses ecx ebx from:DWORD, to:DWORD

mov ebx, to
mov ecx, from
add ecx, 05h
sub ebx, ecx
lea ecx, lgJmp
mov byte ptr , 0E9h
mov dword ptr , ebx
invoke WriteMem, from, addr lgJmp, 5
ret

JmpPatch endp

ResourceHack PROTO :DWORD

.Data

.Data?

HndHook dd ?

.Code

HotKeys proc nCode:DWORD, wParam:DWORD, lParam:DWORD
.if nCode != HC_ACTION jmp HotKeys_End
.endif

mov ebx, lParam
or ebx, 00FFFFFFh
.if ebx == 0C0FFFFFFh ; WM_KEYUP
jmp HotKeys_End
.endif

.if wParam == VK_F11 ; what i want displayed
invoke ResourceHack, 0057F0D8h
invoke BWTextDisplay, CTEXT ("Offline Mineral hack")

.elseif wParam == VK_F12
invoke ResourceHack,  0057F108h
invoke BWTextDisplay, CTEXT ("Offline Gas hack")

.endif

HotKeys_End:
invoke CallNextHookEx, HndHook, nCode, wParam, lParam ; Call next hook in chain
ret

HotKeys endp

DLLProc proc

invoke FindWindow, CTEXT ("SWarClass"), 0 ; Get Starcraft window handle
invoke GetWindowThreadProcessId, eax, 0 ; Get Starcraft's Thread ID
invoke SetWindowsHookEx, WH_KEYBOARD, addr HotKeys, NULL, eax ; Hook our hotkey function
mov HndHook, eax
; Save the handle to our hook Events:
; Events - Here we keep our thread in a loop.
xor eax, eax
jmp Events

DLLProc endp

ResourceHack proc uses eax ebx ecx Resource:DWORD

mov ebx, 0512684h xor eax, eax mov al, byte ptr mov ebx, Resource mov ecx, dword ptr add ecx, 000f4240h mov dword ptr , ecx ret

ResourceHack endp

StartupMsg proc

pushad ; Preserve all registers
invoke BWTextDisplay, CTEXT ("Eradicated beta1") ; Print text
popad ; Restore all registers
ret
StartupMsg endp


.386
.Model Flat, StdCall
OPTION CASEMAP :NONE

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\debug.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\debug.lib

include Basic.inc
include Events.inc

.Data

JmpByte db 0EBh

.Data?

ThreadID dd ?
hThread dd ?

.code

DllEntryPoint proc hInstDLL:DWORD, reason:DWORD, unused:DWORD

mov eax,reason
.if eax == DLL_PROCESS_ATTACH
call DLLStartup patches
invoke CreateThread, NULL, 0, addr DLLProc, 0, 0, addr ThreadID mov hThread, eax .endif
ret

DllEntryPoint endp

DLLStartup proc



invoke WriteMem, 005122C8h, addr JmpByte, 1 ; change version number

invoke JmpPatch, 0048CD70h, addr StartupMsg ; Game startup message

ret

DLLStartup endp



This explains how to use the prebuilt functions. After hijacking the main thread on startup, it runs LoadLibrary which calls DLLStartup adds in your callback functions and turns around and lets your game continue. for your callbacks, you need to find part of the code that you want your code to run at. pick the start of a line and JmpPatch to your function. This overwrites 5 bytes, so you must execute(in your function) whatever code you overwrote with the JmpPatch, then you must jmp back to the next line of code that you didn't perform in your function. Now you can address memory directly without ReadProcessMemory/WriteProcessMemory This should get you going. You will still need to write the injector program to load the dll into the game.
Posted on 2008-01-25 23:21:31 by jakor