Jump to content

Recommended Posts

Summary :

I need to create a dll with a function(maybe the term is export?) called something like GetModName , when called it will create a dialog box something like this:

dialogsm5.jpg basically a text box and an okay button ( maybe a Cancel button).

This is the tutorial I followed to create a dll : http://edais.mvps.org/Tutorials/CDLL/index.html

I have been searching and trying for ages, but I just cannot figure out a way to make that dialog box in a dll and make it appear. I reckon if I get that working, the rest of the code should be easy enough.

Really long story about what I'm trying to accomplish and why I need this, which no one will probably read :

There is this freeware fighting game called Little Fighter 2 ( http://www.lf2.net ) . It is easily customizable which is why lots of mods are made for it. For a long while(couple of years) the latest version was 1.9 and I hacked it up a bit to create a sort of mod loader ( http://www.lf2mods.com ). It worked by abusing the network screen (the only place which let you type stuff).

Screenshot : http://img363.imageshack.us/img363/1228/screenshotwm7.png

I really don't like this solution because :

* It disables network play

* If you enter the name of a mod which doesn't exist it crashes

* You are always prompted with the screen to choose a mod

Now, on the 10th year anniversary of little fighter 2, the creators decided to make an update. And I saw this as a golden opportunity to make the mod loader the proper way(or atleast a little bit better than before). The plan is to create another item in the main menu called "Load Mod" , if its pressed then it will call the function GetModName from a dll (the dll will be added to the import table of the exe using IIDKing v2.01 http://www.reteam.org/tools.html) which will get a valid name of a mod from the user using a dialog. The rest is all easy.

The only problem I'm having is with the dll part, since I'm a real noob at c++ and can only copy-paste code from different places and connect it together to make it work.

Hopefully someone here will be able to help me, or give me a good nudge in the direction.

PS: Creating a dialog box in a dll is different from creating it in a normal program(as far as I can tell), don't just link me to some basic c++ winapi tutorial, I've searched a lot and can't find anything that covers this (or maybe I'm to stupid to understand).

Link to post
Share on other sites

well ive never done that..but see what you have todo is put the dialog Procedure in the dll

and the templete adn then im guessing Create a function to put everything together something like this

extren _C_ dialogProc

extern _C_ ShowDialog Function

sextern _C_ Dialog Templete

im not sure if you can use resources with dll's ..seems logical enough but idk

but yea you want somethnig like above

i posted a way to load a function from the dll in the wiki a really really long time ago perhaps it will of use to you

Link to post
Share on other sites

Silva!

You don't have to export a function to create a dll, its not necessary! you can simply use a DLL as if it were an EXE

Creating a window from within a DLL is no different than creating a window in an EXE!

Here are the basic rules you must follow for your window to show up and work!

1. The thread which calls CreateWindow/CreateWindowEx must be running for the life of the window! if the thread terminates the window ceases to exist!

2. That same thread must contain the message pump so your window can function! without it your window will just show up as a blank window and wont respond to any messages sent to it!

3. There must be a window procedure for the window your creating! It just specifies what actions to take when certain messages are recieved! (like what to do when the "ok" button is pressed for example)

Ive created a sample project in Microsoft Visual C++ 2008 Express Edition (the free version) So I suggest you get that if you don't already have it so we are on the same page here...

http://www.microsoft.com/express/vc/

I went ahead and downloaded the game since its freeware so I'll actually be testing the DLL I made on the game your trying to make it for...

here's an image of my DLL injected into the game and after I presed F12 to make the window unhide and show itself

LF2mod.png

All I have done is create a window from within the dll upon injection, and setup a hotkey handler so that when you press the "F12" key it shows/hides it self depending on its current status

What is this actually going to do? change a mod or something? Well you'll have to add the code for that but here's the base your looking for.

I re-read your post and you said that you are using a program to modify the IAT(Import Address Table) of the executable it self "lf2.exe" and saving the exe! I don't recommend doing that. A better way is to modify the EXE on the fly while its running instead of permanently! I made a custom dll injector for this game, use it if you don't have a DLL injector of your own...

The InitCommonCtrls thing is there for a good reason, if you don't include it, people will complain that there aren't any controls on the window! So its best just to force initialization of common controls just in case they aren't!

It works like this, when the DLL is loaded/injected (DLL_PROCESS_ATTACH) it creates two threads! the "MainThread" creates the window and window controls (an edit box and an ok button) then it hangs out in the message pump dealing with all the messages the window recieves so it can function...

The "HotkeyHandler" thread just indefinately loops waiting for the F12 key to be pressed, when it's pressed it will either hide or unhide the window depending on its current state, if its hidden it will unhide, if its unhidden it will hide ;) Got It?

Fairly Simple, Now figure out the code you need to "change mods" or whatever your intending this to do...

Here's my question though... Why does it have to be a dll in the first place?

I've modified it slightly so that the window always stays on top of the game's window, just because it was annoying sometimes it was underneath. Also the window is moved into the center of the games window whenever the hotkey is pressed.

Download DLL Project SRC + BINARY: (unzip and place it in your VC++ 2008 "Projects" directory[by default in my documents folder])

http://popeax.com/download/apps/ModLF2.zip

Oh yeah and build it as a "Release" build ;)

Download DLL Injector Project SRC + BINARY

http://popeax.com/download/apps/LF2ModLoader.zip

LF2.png

Just run the injector and then run the game or vice versa, now the injector will say success and exit! press F12 when you are ready to unhide the mod loader window!

have a quick look at the source code:

#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
//ModLF2 DLL v1.1
//Written By Steve8x

void MainThread();
void HotkeyHandler();
void InitCommonCtrls();
//Neat Functions For Creating Window Controls
HWND CreateEditEx(int autoscroll, int passworded, char* Text, int x, int y, int wd, int ht, int id);
HWND CreateTextEx(char* Text, int x, int y, int wd, int ht, int id);
HWND CreateButtonEx(char* Text, int x, int y, int wd, int ht, int id);
HWND CreateGroupEx(char* Text, int x, int y, int wd, int ht, int id);

HINSTANCE hInstance;
HWND hwnd, hModName;
bool ShowHide = 0;

char ModName[260] = {0};

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
   if(ul_reason_for_call == DLL_PROCESS_ATTACH)
   {
       hInstance = hModule;
       CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&MainThread, 0, 0, 0);
       CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&HotkeyHandler, 0, 0, 0);
   }
   else if(ul_reason_for_call == DLL_PROCESS_DETACH)
   {
      //clean up code goes here (if any) this is when the dll unloads (when you quit the game)
   }
    return TRUE;
}

//Window Procedure!
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_COMMAND:
            if(wParam == 420)
            {
                GetWindowTextA(hModName, ModName, 260);
                MessageBoxA(0, ModName, "You Typed", 0);


                //this is when the button is clicked
                //code goes here to change the mod or whatever
            }
            
        case WM_CTLCOLORSTATIC:
                SetBkMode((HDC)wParam, TRANSPARENT);
                return (LRESULT)GetStockObject(WHITE_BRUSH);
            break;

        case WM_LBUTTONDOWN: // drag window from any part of client area
            SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam);
            break;
            
        case WM_CLOSE:
            //if the user hits [X] to close the window just hide it instead of destroy it!
            ShowHide = 0;
            ShowWindow(hwnd, SW_HIDE);
            break;
            
        default:  
            return DefWindowProc (hWnd, message, wParam, lParam);
    }
    return 0;
}

//Main thread which will create and maintain the window!
void MainThread()
{
    MSG Msg;            
    WNDCLASSEX wc;
    
    wc.cbSize = sizeof (WNDCLASSEX);
    wc.hInstance = hInstance;
    wc.lpszClassName = L"Steves_Window_Class";
    wc.lpfnWndProc = WndProc;
    wc.style = CS_DBLCLKS;
    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(101));
    wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(101));
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.lpszMenuName = NULL;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;          
    wc.hbrBackground = (HBRUSH)GetStockObject(0);
    
    RegisterClassEx(&wc);
    
    InitCommonCtrls(); // Force Initialization of Common Controls Library!

    hwnd = CreateWindowExA(0, "Steves_Window_Class", "LF2 MOD LOADER", WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_CLIPSIBLINGS,
            CW_USEDEFAULT, CW_USEDEFAULT, 300, 110, HWND_DESKTOP, 0, hInstance, 0);

    CreateGroupEx("Enter Mod Name", 2, 0, 290, 75, 200);
    hModName = CreateEditEx(1, 0, 0, 8, 35, 220, 20, 300);
    CreateButtonEx("OK!", 236, 35, 50, 20, 420);


    ShowWindow(hwnd, SW_HIDE); //Start Window Hidden
    UpdateWindow(hwnd);

    //Message Pump! Needed So Your Window Can Respond To Messages Sent To It!
    while(GetMessage(&Msg, 0, 0, 0))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
}

void HotkeyHandler()
{
    for(;; Sleep(10)) // indefinate loop, so you need at least a sleep(10) in there for anti-lag since were using getasnyckeystate
    {
        if(GetAsyncKeyState(VK_F12))
        {
            ShowHide = ShowHide ^ 1; // "^" means XOR in C++ in other words if its 1 it will now be zero / vice versa
            
            HWND LF2 = FindWindowA(0, "Little Fighter 2");

            RECT* pRect = new RECT;
            GetWindowRect(LF2, pRect);

            SetWindowPos(hwnd, HWND_TOPMOST, (pRect->left+250), (pRect->top+200), 300, 110, 0);
            ShowWindow(hwnd, ShowHide); // If its 1 it will show the window if its zero it will hide it;)
            Sleep(250);
        }
    }
}



HWND CreateEditEx(int autoscroll, int passworded, char* Text, int x, int y, int wd, int ht, int id)
{
    HWND tmp = 0;
    if(autoscroll == 0 && passworded == 0)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
    else if(autoscroll == 1 && passworded == 0)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
    else if(autoscroll == 0 && passworded == 1)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, ES_PASSWORD | WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
    else if(autoscroll == 1 && passworded == 1)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, ES_AUTOHSCROLL | ES_PASSWORD | WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);

    return tmp;
}

HWND CreateTextEx(char* Text, int x, int y, int wd, int ht, int id)
{
    return CreateWindowExA(0, "STATIC", Text, WS_CHILD | WS_VISIBLE | SS_LEFT, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
}

HWND CreateButtonEx(char* Text, int x, int y, int wd, int ht, int id)
{
    return CreateWindowExA(0, "BUTTON", Text, WS_CHILD | WS_VISIBLE, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
}

HWND CreateGroupEx(char* Text, int x, int y, int wd, int ht, int id)
{
    return CreateWindowExA(0, "BUTTON", Text, BS_GROUPBOX | WS_CHILD | WS_VISIBLE, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
}

void InitCommonCtrls() // Needed Just To Make Sure The Window Controls Appear!
                        //Force Common Controls To Initialize Just Incase They Aren't!
{
    INITCOMMONCONTROLSEX icex; 
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_BAR_CLASSES;
    InitCommonControlsEx(&icex);
}

Link to post
Share on other sites

HOLY CRAP Steve8x your my new idol

i have a small question tho..what if i wanted to load a dialogbox from resources

i have the following...but it dosent show my dialog upon injection....im injecting it into explorer just as a test

#include <windows.h>
#define IDD_DIALOG1 101

bool _stdcall CALLBACK DialogProc(HWND dia,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{ 
    
default:
    DefDlgProc(dia,uMsg,wParam,lParam);
    break;
}
return 0;
}

void _stdcall ShowDialog()
{
    LoadLibrary(L"commct32.lib");
    DialogBox(NULL,MAKEINTRESOURCE(IDD_DIALOG1),HWND_DESKTOP,(DLGPROC)DialogProc);
} 

 void WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)

{

   if (dwReason == DLL_PROCESS_ATTACH)

   {
       ShowDialog();
   }

}

and my .def file

LIBRARY    "ExportDLL"

EXPORTS
ShowDialog @1
DialogProc @2

and i have a resource called IDD_DIALOG1 in a rct file

Link to post
Share on other sites

Here is your first issue:

LoadLibrary(L"commct32.lib");

it is not "commct32.lib" that is wrong.

The correct file is called "comctl32.lib"

But you don't pass that to load library! Its a ".lib" file not a DLL file... You instead have to link to it. In VC++ its as easy as putting a #pragma comment at the top just below your includes...

#pragma comment(lib, "comctl32.lib")

you should also add this include

#include <commctrl.h>

just above the #pragma

your next problem is that you aren't passing an HINSTANCE/HMODULE to the "DialogBox" function. An HINSTANCE is pretty much the same thing as an HMODULE. exe's call it HINSTANCE, dll's call it HMODULE. Its just a handle to a module.

The module handle that you have to pass is the module which contains the dialog resource. Make sure that you've added the resource to the project so that it gets stored in the compiled executable. In this case your adding the resource into the dll, so use the dll's module handle.

Where to get the module handle?

well in a DLL in your main function that every dll needs

which looks something

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)

Yours is wrong

void WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)

Not because of putting the HINSTANCE instead of the HMODULE (since there the same im sure it will work and not make any difference)

but the "void" is the problem. DllMain returns a value!! true or false, 1 or 0 (boolean) to make your dll work you should return TRUE on both DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH

lastly, if your just having your dll do some action when its loaded/injected (DLL_PROCESS_ATTACH) then you don't need to export any functions! exporting functions is only if you wanted to load the dll with a process and call a function from it. If the dll is meant to work alone you don't need to export.

heres a fixed up version how I would've done it:

#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
#define IDD_DIALOG1 101

HINSTANCE ModuleHandle;

bool _stdcall CALLBACK DialogProc(HWND dia,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    switch(uMsg)
    { 
    
        default:
        DefDlgProc(dia,uMsg,wParam,lParam);
        break;

    }
    return 0;
}

void _stdcall ShowDialog()
{
    DialogBox(ModuleHandle, MAKEINTRESOURCE(IDD_DIALOG1), HWND_DESKTOP, (DLGPROC)DialogProc);
} 

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
    if(dwReason == DLL_PROCESS_ATTACH)
    {
        //Copy local variable into global variable
        ModuleHandle = hInstance;

        //Show Dialog Window
        //Create thread instead of call, so this thread doesn't get held up until it returns!
        CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&ShowDialog, 0, 0, 0);
    }
    else if(dwReason == DLL_PROCESS_DETACH)
    {
        
    }

    return TRUE;
}

I don't see why you like doing it that way though. I think its best to dynamically create your windows with CreateWindow at run time, like shown in my previous example ;)

Link to post
Share on other sites

Thanks Steve8x , your solution is awesome for somethings. However, thats not what I'm looking for.

Your solution is kind of temporary, while I'm looking for something more permanent.

26435143wy0.jpg

(actual game running)

I have added another option to the menu, so all people have to do is push it and volia... Your method would require them to run another program, inject the dll etc etc (less user friendly).

So, the only way I can think of properly doing it, would be to make a dll(with an export) and when the user pressed Load Mod, the exe calls that function etc etc.

So if you could do it with a dll using an export function I'd be in your ever lasting debt.

PS: Sorry it took so long to reply, I was making sure I could actually hack up the exe (I'm kinda rusty).

Link to post
Share on other sites
Thanks Steve8x , your solution is awesome for somethings. However, thats not what I'm looking for.

Your solution is kind of temporary, while I'm looking for something more permanent.

26435143wy0.jpg

(actual game running)

I have added another option to the menu, so all people have to do is push it and volia... Your method would require them to run another program, inject the dll etc etc (less user friendly).

So, the only way I can think of properly doing it, would be to make a dll(with an export) and when the user pressed Load Mod, the exe calls that function etc etc.

So if you could do it with a dll using an export function I'd be in your ever lasting debt.

PS: Sorry it took so long to reply, I was making sure I could actually hack up the exe (I'm kinda rusty).

Ok, So you don't like having to run something everytime you play the game. Thats understandable...

Did you actually add that other option to the menu? or did you just draw that on the image lol!

If you actually added that to the menu, how did you do that? using a dll you made? I suspect there is some thing you aren't sharing...

I'm just trying to figure out how you'd want it. So when you press that load mod option from the menu you want the mod loader window to show up?

Anyway I've come up with a way for a more permanent solution. Patch the executable so it calls LoadLibrary on your DLL before it does anything else.

You can either do this manually with OllyDbg (what I use) or code a patcher for it. And I've done just that!

LF2Patcher.png

Its called LF2 Patcher. It first saves a backup of the original lf2.exe as "lf2_backup.exe" if it hasn't already done so! And uses the backup to read from(this way if you accidentally run the patcher twice it wont overwrite the backup with a patched version)

Next it reads the lf2_backup.exe into memory, then it finds a code cave! a code cave is a portion of memory that is blank (0's). The code cave will be used to put the necessary code to load the dll of choice at runtime...

It sets up everything for the codecave, and puts the load library address + the original call address + the dll string all into the code cave, then finally it puts the code into the codecave...

then to make it actually work you need to hook the entry point of the executable so that when it runs it calls the code in the codecave then continues running onto its code...

I figured out the entry point by opening lf2.exe up in OllyDbg.

LF2OEP.png

When you open it up and give it a second it will show up like that! The highlighted line also marked with a "$" is the entry point.

The code at the entry point is perfect for a hook! calls always make a nice place to hook. All you have to do is change the 4 bytes(the jump offset) after E8 so that it calls the loadlibrary code in the codecave. Then to not mess anything up you also call the original address

So as you can see the EntryPointAddress is 0x4456E0 and the CallAddress is 0x445B31

EDIT: The patcher now figures out the Entry Point Address and Call Address on its own! So you wont have to manually update the addresses!!

Here is what the patched lf2.exe looks like in olly when you follow the call instruction at the entry point to the code cave

LF2CodeCave.png

Simple enough yeah?

LF2 Patcher updated v1.1, a Dev C++ Project including binary and source code:

http://popeax.com/download/apps/LF2Patcher-1.1.zip

An already patched lf2.exe to load "ModLF2.dll" that you can test: (click load mod for the mod loader window to show up)

http://popeax.com/download/apps/LF2Patched_loadmod.zip

Instructions:

1. Place LF2Patcher.exe into your LF2 folder where lf2.exe is located.

2. Place a dll named "ModLF2.dll" into the same folder (modify the source and compile if you want to change the name of the dll which gets loaded)

3. Run LF2Patcher.exe and follow the simple instructions.

Once it says "lf2.exe Patched Successfully!" then you can press any key to quit the patcher. Now test the patched lf2.exe!

Now anytime you run lf2.exe your dll will load everytime without having to run a separate injector!

Thats about as permanent as you can get it ;)

As a final note I'm not sure whether this will work on vista or not! I have only tested it on XP! So anyone who test's this and has vista make a post on if it works or not :P

Take a glance:

//LF2 Patcher - By Steve8x
//Place this executable in your LF2 Directory where LF2.exe resides!
//Then run it!
//v1.1 - made it find entry point address on its own :P
#include <windows.h>
#include <fstream>

//ScanAOB a function I made which will scan for a byte pattern! including wildcards '?'
DWORD ScanAOB(char* AOB, char* memdump, DWORD searchsize, int aobsize);
char* FindCodeCave(int cavesize);
DWORD getFileSize(FILE* pfile);

DWORD EntryPointAddress = 0;
DWORD EntryPointOffset = 0;
DWORD LoadLibAddress = 0;
DWORD CallAddress = 0;
DWORD fSize = 0;
FILE* f = 0;

//this array of bytes(AOB) is used to find the entry point;)
//its a unique byte pattern of the code found at the entry point!
char arrayofbytes[] = {0xE8, '?', '?', '?', '?', 0xE9, '?', '?', '?', '?', 0x55, 0x8B, 0xEC, 0x81, 0xEC, 0x28, 0x03, 0x00, 0x00};
char* DllName = "ModLF2.dll"; //Put the name of the DLL you want loaded here...
char* filebuffer = 0;
char* codecave = 0;
bool success = 0;

int main()
{
    SetConsoleTitleA("LF2 Patcher!");
    system("color 0A");
    
    printf("This will patch lf2.exe so that it loads \"%s\" when you run it;)\n\n", DllName);
    
    success = CopyFileA("lf2.exe", "lf2_backup.exe", TRUE);
    if(success == 0)
    {
        printf("You have already made a backup! So your fine!;)\n");
        system("pause"); // Press Any Key To Continue...
    }
    else
    {
        printf("Backup named \"lf2_backup.exe\" was made successfully!\n");
        system("pause"); 
    }
    
    LoadLibAddress = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    
    f = fopen("lf2_backup.exe", "rb"); // open lf2.exe for reading
    
    fSize = getFileSize(f);

    filebuffer = new char[fSize]; // allocate space for the file in memory
    fread(filebuffer, fSize, 1, f); // read entire file into buffer
    fclose(f);
    
    if(EntryPointAddress == 0)
    {
        //Piece of cake
        EntryPointAddress = ScanAOB(arrayofbytes, filebuffer, fSize, sizeof(arrayofbytes));
    }
    
    EntryPointOffset = EntryPointAddress - 0x400000;
    
    codecave = FindCodeCave(100); //Locate a codecave to put the load library code and strings

    char* EP = filebuffer + EntryPointOffset; //(start of lf2.exe loaded in mem + Entry Point Offset)
    
    //Entry Point Address + Jump Offset + 5 = address being called at entry point
    CallAddress = ((EntryPointAddress + *(DWORD*)&EP[1]) + 5);
    
    DWORD pLoadLib = (DWORD)codecave;
    DWORD pCallAddy = (DWORD)codecave + 4;
    
    *(DWORD*)pLoadLib = LoadLibAddress;
    *(DWORD*)pCallAddy = CallAddress;
    
    char* dllstringaddress = codecave + 9;
    strcpy(dllstringaddress, DllName);
    
    char* codeforcave = (dllstringaddress + (strlen(DllName) + 1));
    
    //Fix Addresses So In The Real Executable They Work!;)
    //Subtract image base of the exe loaded in memory in this app
    //Add REAL image base (0x400000)
    DWORD pLoadLib_fixed = ((pLoadLib - (DWORD)filebuffer) + 0x400000);
    DWORD pCallAddy_fixed = ((pCallAddy - (DWORD)filebuffer) + 0x400000);
    DWORD pDllString_fixed = (((DWORD)dllstringaddress - (DWORD)filebuffer) + 0x400000);
    
    *(BYTE*)&codeforcave[0] = 0x68;                 //PUSH [dllstringaddress]
    *(DWORD*)&codeforcave[1] = (DWORD)pDllString_fixed;
    
    *(WORD*)&codeforcave[5] = 0x15FF;             //CALL [LoadLibraryA]
    *(DWORD*)&codeforcave[7] = (DWORD)pLoadLib_fixed;
    
    *(WORD*)&codeforcave[11] = 0x15FF;           //CALL [originaladdress]
    *(DWORD*)&codeforcave[13] = (DWORD)pCallAddy_fixed;
    
    *(BYTE*)&codeforcave[17] = 0xC3; // RETURN
    
    //Hook The Entry Point So It Calls Our CodeCave When Ran Which Then Calls LoadLibrary And The Original Call Then Returns;)
    DWORD jumpoffset = (DWORD)codeforcave - (DWORD)EP - 5;
    *(DWORD*)&EP[1] = jumpoffset;
    
    
    DWORD codecaveoffset = codecave - filebuffer;
    printf("\nlf2.exe In Memory, Base Address: %X\nCode Cave Offset: %X\nFound Entry Point: %X\nCalculated Call Address: %X\nLoadLibraryA Address: %X\n\n", filebuffer, codecaveoffset, EntryPointAddress, CallAddress, LoadLibAddress);
    
    //Save Patched File
    f = fopen("lf2.exe", "wb");
    fwrite(filebuffer, fSize, 1, f);
    fclose(f);
    
    printf("lf2.exe Patched Successfully!\n");
    system("pause");
    
    //Clean up
    delete[] filebuffer;
    return 1;
}

DWORD ScanAOB(char* AOB, char* memdump, DWORD searchsize, int aobsize)
{
    unsigned long a = 0, i = 0;
    
    for(i = 0; i < searchsize; i++)
    {      
        while(*(BYTE*)&AOB[a] == '?')
        {
            a++;
            i++;
        }
        if(*(BYTE*)&memdump[i] == *(BYTE*)&AOB[a])
        {
            if(a == (aobsize - 1))
            {
                DWORD addy = (DWORD)&memdump[i-a];
                addy -= (DWORD)&memdump[0];
                addy += 0x400000;
                return addy;
            }
            a++;
        }
        else
        {
            a = 0;
        }
    }
    return 0;
}

char* FindCodeCave(int cavesize)
{
    DWORD x = 0;
    
    for(DWORD i = EntryPointOffset; i < fSize; i++)
    {
        if(*(BYTE*)&filebuffer[i] == 0)
        {
            for(x = 0; x < cavesize; x++)
            {
                if(*(BYTE*)&filebuffer[i+x] != 0)
                {
                    break;
                }
            }
            
            if(x == cavesize)
            {
                return &filebuffer[i];
            }
        }
    }
    return 0;
}

DWORD getFileSize(FILE* pfile)
{
    DWORD theSize = 0;
    
    fseek(pfile, 0, SEEK_END);
    theSize = ftell(pfile);
    rewind(pfile);
    
    return theSize;
}

Link to post
Share on other sites

Hi steve8x. I have already added the option to the menu with a bit of exe hacking (sorry if I haven't made that clear before). Heres the exe you can see it for your self.

http://www.mediafire.com/?oeejw9tdjqz

(Nothing actually happens when you press Load Mod, didn't have the time to code that bit yet but it is easy enough) My poorly written code starts at 00446334.

I'm quite proficient in dissembling/debugging/cracking (what ever you feel like calling it). I've never used the LoadLibaryA api though, but I kind of get how it works.

Everything is starting to look good now, the only problem I see is how will the dll know when the button is pressed? If it was an export function all I'd have to do is type "CALL ADDRESS" in the part of the code which deals with what happens when the button is clicked.

There is also another really small disadvantage to using your method, since it runs in a seperate thread, lf2 will keep running while you are suppoused to enter the mod name. Not to much of an issue though, I have an idea on how to get around that (involves an infinite loop until the mod is entered :D ).

PS: Thanks for being so helpful! Last time I was doing this no one even bothered to (probably should of asked on the hak5 forums :P ).

Edit: Yes, this thread has lots of awesome code in it which I might reuse for other things (with credit of course :P).

Link to post
Share on other sites
Hi steve8x. I have already added the option to the menu with a bit of exe hacking (sorry if I haven't made that clear before). Heres the exe you can see it for your self.

http://www.mediafire.com/?oeejw9tdjqz

(Nothing actually happens when you press Load Mod, didn't have the time to code that bit yet but it is easy enough) My poorly written code starts at 00446334.

I'm quite proficient in dissembling/debugging/cracking (what ever you feel like calling it). I've never used the LoadLibaryA api though, but I kind of get how it works.

Everything is starting to look good now, the only problem I see is how will the dll know when the button is pressed? If it was an export function all I'd have to do is type "CALL ADDRESS" in the part of the code which deals with what happens when the button is clicked.

There is also another really small disadvantage to using your method, since it runs in a seperate thread, lf2 will keep running while you are suppoused to enter the mod name. Not to much of an issue though, I have an idea on how to get around that (involves an infinite loop until the mod is entered :D ).

PS: Thanks for being so helpful! Last time I was doing this no one even bothered to (probably should of asked on the hak5 forums :P ).

Edit: Yes, this thread has lots of awesome code in it which I might reuse for other things (with credit of course :P).

How will the dll know when the button is pressed? well I don't know where in the game code gets executed when you click the load mod option... But I have thought of a work around!

Basically when the mouse is clicked, you get the mouse pointers coordinates, then convert them to the coordinates relevant to the games window, then if they are within a certain boundary (the load mod option) unhide the window! if not do nothing! All of this is done from within the dll...

I've changed the dll's source code so it no longer has a hotkeyhandler (for the f12 press) but instead has a mouse click handler!

There is also another really small disadvantage to using your method, since it runs in a seperate thread, lf2 will keep running while you are suppoused to enter the mod name. Not to much of an issue though, I have an idea on how to get around that (involves an infinite loop until the mod is entered :D ).

I don't get what you mean really... How is that a disadvantage? Doesn't the game have to be running for you to load a mod for it? Even your load mod option on the menu is only clickable if the game is running lol... The game should be kept running (unless it has to quit to load a mod? is that the case? if so you'll have to make a seperate module then! [an exe] since once you terminate lf2 your dll will be ejected! and any threads it had running will be terminated :P)

Anyway check my previous post to get the updated patcher which is better than the first because it finds the Entry Point Address on its own... instead of relying on you to put it in the source!

Then once you've got that use it to patch your modified exe which has the "load mod" menu option added. Then put the new dll [posted below] in the same dir... now run lf2.exe and click the load mod option! voila! the window shows up when you click it!

Now all you have to do is write the code to actually LOAD THE MOD! :P

http://popeax.com/download/apps/ModLF2-1.2.zip

#include <windows.h>
#include <stdio.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
//ModLF2 DLL v1.2
//Written By Steve8x

void MainThread();
void MouseClickHandler();
void RelocateWindow(int addX, int addY);
void InitCommonCtrls();
//Neat Functions For Creating Window Controls
HWND CreateEditEx(int autoscroll, int passworded, char* Text, int x, int y, int wd, int ht, int id);
HWND CreateButtonEx(char* Text, int x, int y, int wd, int ht, int id);
HWND CreateGroupEx(char* Text, int x, int y, int wd, int ht, int id);

HINSTANCE hInstance;
HWND hwnd, hModName, LF2;

POINT* p = new POINT;
RECT* pRect = new RECT;
char* ModName = new char[260];
char* dbg = new char[260];

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
   if(ul_reason_for_call == DLL_PROCESS_ATTACH)
   {
       hInstance = hModule;
       CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&MainThread, 0, 0, 0);
       CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&MouseClickHandler, 0, 0, 0);
   }
   else if(ul_reason_for_call == DLL_PROCESS_DETACH)
   {
       delete[] ModName;
       delete[] dbg;
       delete p;
       delete pRect;
      //clean up code goes here (if any) this is when the dll unloads (when you quit the game)
   }
    return TRUE;
}

//Window Procedure!
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_COMMAND:
            if(wParam == 420)
            {
                GetWindowTextA(hModName, ModName, 260);
                MessageBoxA(0, ModName, "You Typed:", 0);

                //this is when the button is clicked
                //code goes here to load the mod or whatever
                //CreateThread recommended
            }
            
        case WM_CTLCOLORSTATIC:
                SetBkMode((HDC)wParam, TRANSPARENT);
                return (LRESULT)GetStockObject(WHITE_BRUSH);
            break;

        case WM_LBUTTONDOWN: // drag window from any part of client area
            SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam);
            break;
            
        case WM_CLOSE:
            //if the user hits [X] to close the window just hide it instead of destroy it!
            ShowWindow(hwnd, SW_HIDE);
            RelocateWindow(250, 200);
            break;
            
        default:  
            return DefWindowProc (hWnd, message, wParam, lParam);
    }
    return 0;
}

//Main thread which will create and maintain the window!
void MainThread()
{
    MSG Msg;            
    WNDCLASSEX wc;
    
    wc.cbSize = sizeof (WNDCLASSEX);
    wc.hInstance = hInstance;
    wc.lpszClassName = L"Steves_Window_Class";
    wc.lpfnWndProc = WndProc;
    wc.style = CS_DBLCLKS;
    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(101));
    wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(101));
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.lpszMenuName = NULL;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;          
    wc.hbrBackground = (HBRUSH)GetStockObject(0);
    
    RegisterClassEx(&wc);
    
    InitCommonCtrls(); // Force Initialization of Common Controls Library!

    hwnd = CreateWindowExA(0, "Steves_Window_Class", "LF2 MOD LOADER", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_CLIPSIBLINGS,
            CW_USEDEFAULT, CW_USEDEFAULT, 300, 110, HWND_DESKTOP, 0, hInstance, 0);

    CreateGroupEx("Enter Mod Name", 2, 0, 290, 75, 200);
    hModName = CreateEditEx(1, 0, 0, 8, 35, 220, 20, 300);
    CreateButtonEx("OK!", 236, 35, 50, 20, 420);

    RelocateWindow(250, 200);

    //Message Pump! Needed So Your Window Can Respond To Messages Sent To It!
    while(GetMessage(&Msg, 0, 0, 0))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
}

void MouseClickHandler()
{
    for(;; Sleep(10)) // indefinate loop, so you need at least a sleep(10) in there for anti-lag since were using getasnyckeystate
    {
        if(GetAsyncKeyState(VK_LBUTTON)) //if left mouse button is clicked...
        {
            GetCursorPos(p);        // get cursor screen coordinates
            ScreenToClient(LF2, p); // convert screen coords to window coords

            if(p->x > 345 && p->x < 438)
            {
                if(p->y > 368 && p->y < 389)
                {
                    //if the cursor is within the boundaries of the load mod option...
                    //--------------------------------------------------------------->
                    RelocateWindow(250, 200);
                    ShowWindow(hwnd, SW_SHOW);
                    Sleep(250);
                    //<---------------------------------------------------------------
                }
            }

            //uncomment this code when getting the coordinates
            //sprintf(dbg, "X-> %i Y-> %i", p->x, p->y);
            //OutputDebugStringA(dbg);
            //Sleep(250);
        }
    }
}

void RelocateWindow(int addX, int addY)
{
    LF2 = FindWindowA(0, "Little Fighter 2");
    GetWindowRect(LF2, pRect);
    SetWindowPos(hwnd, HWND_TOPMOST, (pRect->left+addX), (pRect->top+addY), 300, 110, 0);
}

HWND CreateEditEx(int autoscroll, int passworded, char* Text, int x, int y, int wd, int ht, int id)
{
    HWND tmp = 0;
    if(autoscroll == 0 && passworded == 0)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
    else if(autoscroll == 1 && passworded == 0)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
    else if(autoscroll == 0 && passworded == 1)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, ES_PASSWORD | WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
    else if(autoscroll == 1 && passworded == 1)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, ES_AUTOHSCROLL | ES_PASSWORD | WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);

    return tmp;
}

HWND CreateButtonEx(char* Text, int x, int y, int wd, int ht, int id)
{
    return CreateWindowExA(0, "BUTTON", Text, WS_CHILD | WS_VISIBLE, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
}

HWND CreateGroupEx(char* Text, int x, int y, int wd, int ht, int id)
{
    return CreateWindowExA(0, "BUTTON", Text, BS_GROUPBOX | WS_CHILD | WS_VISIBLE, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
}

void InitCommonCtrls() // Needed Just To Make Sure The Window Controls Appear!
{
    INITCOMMONCONTROLSEX icex; 
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_BAR_CLASSES;
    InitCommonControlsEx(&icex);
}

Link to post
Share on other sites

I think I found a way to get this to work.

00446438     393D 80754500  CMP DWORD PTR DS:[457580],EDI   \\ check if mouse is clicked
0044643E    ^0F85 C018FEFF  JNZ mod_load.00427D04    \\ if not clicked then just skip all this code
00446444     391D 60D04400  CMP DWORD PTR DS:[44D060],EBX   \\ I'm guessing another check if mouse is clicked
0044644A    ^0F85 B418FEFF  JNZ mod_load.00427D04   \\ if not clicked this skip all this code
00446450     53             PUSH EBX   \\ sound stuff
00446451     B9 10564500    MOV ECX,mod_load.00455610   \\ sound stuff
00446456     E8 D5B5FBFF    CALL mod_load.00401A30   \\ sound stuff
0044645B     C605 789F4500 >MOV BYTE PTR DS:[459F78],1  \\ moves  1 to 459F78 (just a random place i choose)
00446462     803D 789F4500 >CMP BYTE PTR DS:[459F78],1   \\ checks if 459F78 = 1
00446469    ^74 F7          JE SHORT mod_load.00446462  \\ jumps back to the cmp above if it is 1(basically an infinite loop)
0044646B    ^E9 9418FEFF    JMP mod_load.00427D04  \\ jumps out of the codecave to the rest of the code

The idea is the dll will constantly check 459F78 to see if it is 1, if it is then the dialog box will appear. After the user presses the okay button it it will write 0 to 459F78 (which will then stop the loop so little fighter can keep running normally).

Now the only problem is I don't know how to read the memory using a dll. I remember there was a windows api to do such a thing (I believe it was something like ReadProcessMemory), but will that work inside a dll? And isn't there a better to do it (since the dll should be sharing the applications memory, I'm guessing the api isn't needed ).

Edit : Ouch, looks like we were both typing at the same time :P . Your solution looks better than mine. Thank you for all the help man. I'll try and get this all working :D

Link to post
Share on other sites
I think I found a way to get this to work.

00446438     393D 80754500  CMP DWORD PTR DS:[457580],EDI   \\ check if mouse is clicked
0044643E    ^0F85 C018FEFF  JNZ mod_load.00427D04    \\ if not clicked then just skip all this code
00446444     391D 60D04400  CMP DWORD PTR DS:[44D060],EBX   \\ I'm guessing another check if mouse is clicked
0044644A    ^0F85 B418FEFF  JNZ mod_load.00427D04   \\ if not clicked this skip all this code
00446450     53             PUSH EBX   \\ sound stuff
00446451     B9 10564500    MOV ECX,mod_load.00455610   \\ sound stuff
00446456     E8 D5B5FBFF    CALL mod_load.00401A30   \\ sound stuff
0044645B     C605 789F4500 >MOV BYTE PTR DS:[459F78],1  \\ moves  1 to 459F78 (just a random place i choose)
00446462     803D 789F4500 >CMP BYTE PTR DS:[459F78],1   \\ checks if 459F78 = 1
00446469    ^74 F7          JE SHORT mod_load.00446462  \\ jumps back to the cmp above if it is 1(basically an infinite loop)
0044646B    ^E9 9418FEFF    JMP mod_load.00427D04  \\ jumps out of the codecave to the rest of the code

The idea is the dll will constantly check 459F78 to see if it is 1, if it is then the dialog box will appear. After the user presses the okay button it it will write 0 to 459F78 (which will then stop the loop so little fighter can keep running normally).

Now the only problem is I don't know how to read the memory using a dll. I remember there was a windows api to do such a thing (I believe it was something like ReadProcessMemory), but will that work inside a dll? And isn't there a better to do it (since the dll should be sharing the applications memory, I'm guessing the api isn't needed ).

Edit : Ouch, looks like we were both typing at the same time :P . Your solution looks better than mine. Thank you for all the help man. I'll try and get this all working :D

Well actually yours is better if its the right place that checks whether the mouse is clicked on your load mod option! I'll tinker with it to see if I can get your method to work! 2 ways is better than 1 way ;)

Yeah when your inside a process's address space either from within a dll or just plain inside of it (where your modifying the exe just like your doing) You could use readprocessmemory but since you don't need to its best not to use it!

Instead deal directly with the memory!

ReadProcessMemory just reads a process's memory and copies it into a buffer of your choice! but you already have your boolean value stored in a buffer (a 1 byte buffer lol)

459F78

you deal with memory exactly how your doing it!

in assembly:

MOV BYTE PTR [459F78], 1

in c++:

*(BYTE*)0x459F78 = 1;

in assembly:

CMP BYTE PTR [459F78], 1

JE mouseclicked

JNE mousenotclicked

in c++:

if(*(BYTE*)0x459F78 == 1)

{

goto mouseclicked;

}

else

{

goto mousenotclicked;

}

Putting This: (BYTE*)

means that you want to treat what you put after it as a pointer to a byte(1byte/8bits)...

Putting This: (DWORD*)

means you want to treat whats after as a pointer to a DWORD(4bytes/32bits)

There is also (WORD*)

so writing this

(BYTE*)0x459F78

means your casting 459F78 as a pointer to a byte. you could cast it as a WORD if you wanted to modify two bytes at that address instead of one, or a dword to modify 4 bytes.

to modify whats at that address though since we are dealing with a pointer here, you have to dereference it!

thats where the star * comes into play

put it before the cast

so

*(BYTE*)0x459F78 = 0x01;

means we are changing the byte pointed to by address 0x459F78 to binary 01

I think you'll figure it out just look at some of the code and it'll make sense :P

Thats what coding is about really, just moving little bits and bytes around... You can't move more than 32 bits at once (well at least in the 32bit world) You can however move them around one after another in like a loop :P

what I mean by that is say for example you wanted to clear a 1000 byte block of memory (and lets pretend functions to do so didnt exist)

you'd have to make your own function... you can't just write 1 instruction which will zero out the 1000 bytes. Since you can only work with a max of 32 bits (4 bytes) at a time...

here's what I came up with. use it like "ClearMemory(pointertomemtoerase, sizeofmemtoerase);"

it starts zeroing out the memory 4 bytes at a time so long as there are 4 or more bytes left to zero out! then once theirs less than 4 bytes it just finishes it off with 1 byte at a time... So which way is faster? zeroing out all the bytes 1 byte at a time? or zeroing it out 4 bytes at a time until you can't anymore? I'll let you decide :P

void ClearMemory(void* memblock, DWORD blocksize)
{
    DWORD i = 0;
    DWORD bytesleft = 0;

    while(i < blocksize)
    {
        bytesleft = blocksize - i;

        if(bytesleft >= 4)
        {
            *(DWORD*)&memblock[i] = 0;
            i += 4;
        }
        else
        {
            *(BYTE*)&memblock[i] = 0;
                        i++;
        }
    }
}

Link to post
Share on other sites

I got it to work using my method !

My code is probably crap, but yeah... I tried to get the window to close after you press okay... Sadly it didn't work for me.

Heres the download (includes the compiled dll and the modified exe needed to make it work):

http://www.mediafire.com/?wx0mw1rxdsz

And here is the source code (which is probably terrible) :

#include <windows.h>
#include <stdio.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
//ModLF2 DLL v1.2
//Written By Steve8x

void MainThread();
void MouseClickHandler();
void RelocateWindow(int addX, int addY);
void InitCommonCtrls();
//Neat Functions For Creating Window Controls
HWND CreateEditEx(int autoscroll, int passworded, char* Text, int x, int y, int wd, int ht, int id);
HWND CreateButtonEx(char* Text, int x, int y, int wd, int ht, int id);
HWND CreateGroupEx(char* Text, int x, int y, int wd, int ht, int id);

HINSTANCE hInstance;
HWND hwnd, hModName, LF2;

POINT* p = new POINT;
RECT* pRect = new RECT;
char* ModName = new char[260];
char* dbg = new char[260];

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
   if(ul_reason_for_call == DLL_PROCESS_ATTACH)
   {
       hInstance = hModule;
       CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&MainThread, 0, 0, 0);
       CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&MouseClickHandler, 0, 0, 0);
   }
   else if(ul_reason_for_call == DLL_PROCESS_DETACH)
   {
       delete[] ModName;
       delete[] dbg;
       delete p;
       delete pRect;
      //clean up code goes here (if any) this is when the dll unloads (when you quit the game)
   }
    return TRUE;
}

//Window Procedure!
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_COMMAND:
            if(wParam == 420)
            {
                GetWindowTextA(hModName, ModName, 260);
                *(BYTE*)0x459F78 = 0x00;
                WM_CLOSE;
            }
            
        case WM_CTLCOLORSTATIC:
                SetBkMode((HDC)wParam, TRANSPARENT);
                return (LRESULT)GetStockObject(WHITE_BRUSH);
            break;

        case WM_LBUTTONDOWN: // drag window from any part of client area
            SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam);
            break;
            
        case WM_CLOSE:
            //if the user hits [X] to close the window just hide it instead of destroy it!
            ShowWindow(hwnd, SW_HIDE);
            RelocateWindow(250, 200);
            break;
            
        default:  
            return DefWindowProc (hWnd, message, wParam, lParam);
    }
    return 0;
}

//Main thread which will create and maintain the window!
void MainThread()
{
    MSG Msg;            
    WNDCLASSEX wc;
    
    wc.cbSize = sizeof (WNDCLASSEX);
    wc.hInstance = hInstance;
    wc.lpszClassName = L"Steves_Window_Class";
    wc.lpfnWndProc = WndProc;
    wc.style = CS_DBLCLKS;
    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(101));
    wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(101));
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.lpszMenuName = NULL;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;          
    wc.hbrBackground = (HBRUSH)GetStockObject(0);
    
    RegisterClassEx(&wc);
    
    InitCommonCtrls(); // Force Initialization of Common Controls Library!

    hwnd = CreateWindowExA(0, "Steves_Window_Class", "LF2 MOD LOADER", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_CLIPSIBLINGS,
            CW_USEDEFAULT, CW_USEDEFAULT, 300, 110, HWND_DESKTOP, 0, hInstance, 0);

    CreateGroupEx("Enter Mod Name", 2, 0, 290, 75, 200);
    hModName = CreateEditEx(1, 0, 0, 8, 35, 220, 20, 300);
    CreateButtonEx("OK!", 236, 35, 50, 20, 420);

    RelocateWindow(250, 200);

    //Message Pump! Needed So Your Window Can Respond To Messages Sent To It!
    while(GetMessage(&Msg, 0, 0, 0))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
}

void MouseClickHandler()
{
    for(;; Sleep(10)) // indefinate loop, so you need at least a sleep(10) in there for anti-lag since were using getasnyckeystate
    {
        if(*(BYTE*)0x459F78 == 1)
        {
               RelocateWindow(250, 200);
               ShowWindow(hwnd, SW_SHOW);
               Sleep(250);
        }
    }
}

void RelocateWindow(int addX, int addY)
{
    LF2 = FindWindowA(0, "Little Fighter 2");
    GetWindowRect(LF2, pRect);
    SetWindowPos(hwnd, HWND_TOPMOST, (pRect->left+addX), (pRect->top+addY), 300, 110, 0);
}

HWND CreateEditEx(int autoscroll, int passworded, char* Text, int x, int y, int wd, int ht, int id)
{
    HWND tmp = 0;
    if(autoscroll == 0 && passworded == 0)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
    else if(autoscroll == 1 && passworded == 0)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
    else if(autoscroll == 0 && passworded == 1)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, ES_PASSWORD | WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
    else if(autoscroll == 1 && passworded == 1)
        tmp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", Text, ES_AUTOHSCROLL | ES_PASSWORD | WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_TABSTOP, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);

    return tmp;
}

HWND CreateButtonEx(char* Text, int x, int y, int wd, int ht, int id)
{
    return CreateWindowExA(0, "BUTTON", Text, WS_CHILD | WS_VISIBLE, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
}

HWND CreateGroupEx(char* Text, int x, int y, int wd, int ht, int id)
{
    return CreateWindowExA(0, "BUTTON", Text, BS_GROUPBOX | WS_CHILD | WS_VISIBLE, x, y, wd, ht, hwnd, (HMENU)id, hInstance, 0);
}

void InitCommonCtrls() // Needed Just To Make Sure The Window Controls Appear!
{
    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_BAR_CLASSES;
    InitCommonControlsEx(&icex);
}

Link to post
Share on other sites
I got it to work using my method !

My code is probably crap, but yeah... I tried to get the window to close after you press okay... Sadly it didn't work for me.

Heres the download (includes the compiled dll and the modified exe needed to make it work):

http://www.mediafire.com/?wx0mw1rxdsz

I've played around with it and yeah your method is better. Because you don't have to mess around with coordinates, the game tells you whether the option was clicked or not! And it even makes that cool noise when you click it unlike my workaround...

Your code was not terrible, not at all and you had it almost right!

There were a couple issues with what you did. First by trapping the game in an infinite loop

with this assembly code here:

0044645B     C605 789F4500 >MOV BYTE PTR DS:[459F78],1  \\ moves  1 to 459F78 (just a random place i choose)
00446462     803D 789F4500 >CMP BYTE PTR DS:[459F78],1   \\ checks if 459F78 = 1
00446469    ^74 F7          JE SHORT mod_load.00446462  \\ jumps back to the cmp above if it is 1(basically an infinite loop)
0044646B    ^E9 9418FEFF    JMP mod_load.00427D04  \\ jumps out of the codecave to the rest of the code

Now the game is frozen, trying to do anything in the game it will not respond. The mod loader window however works, but also because that value 459F78 is equal to 1 this code in the dll will run constantly as well...

if(*(BYTE*)0x459F78 == 1)
        {
               RelocateWindow(250, 200);
               ShowWindow(hwnd, SW_SHOW);
               Sleep(250);
        }

so it will be kind of annoying the window constantly being moved and unhidden every 250 milliseconds. If the user wanted to cancel loading a mod he would not be able to! and the game would be frozen until he either loaded a mod or ended task on the game! I don't think that's how you'd want it!

So to prevent the game locking up, and the mod loader window from being unable to close it

You simply change that if so that it sets that address 0x459F78 back to zero :P

so here's the new code:

void MouseClickHandler()
{
    for(;; Sleep(10)) // indefinate loop, so you need at least a sleep(10) in there for anti-lag since were using getasnyckeystate
    {
        if(*(BYTE*)0x459F78 == 0x01)
        {
            //set it back to zero so the game doesn't freeze in that infinite loop you made!
            //and so this "if" isn't always true other wise it will keep showing the window and moving it
            *(BYTE*)0x459F78 = 0x00;

            RelocateWindow(250, 200);
            ShowWindow(hwnd, SW_SHOW);
            Sleep(250);
        }
    }
}

Now adding that 1 simple line there without changing anything else, solves both issues! The game no longer locks up, and the window can be closed by hitting [X], and it wont show up again unless load mod is clicked once again.

Now making the window hide when the "OK" button is pressed is easy too!

heres what you had:

case WM_COMMAND:
            if(wParam == 420)
            {
                GetWindowTextA(hModName, ModName, 260);
                *(BYTE*)0x459F78 = 0x00;
                WM_CLOSE;
            }

first off you can remove the "*(BYTE*)0x459F78 = 0x00;" line because by this time it is already zero... when the user clicked the load mod button it set this address's value to 1 as a trigger. The dll is constantly checking for it to be 1 so when it is, it triggers the show window code and then sets it back to zero to reset it so it can do the same thing over...

Next you had it somewhat close

WM_CLOSE

but you CAN'T just write that, its a window message! You CAN send it to the mod loader window with...

SendMessage(hwnd, WM_CLOSE, 0, 0);

hwnd being the window handle of the mod loader window

but take a peak in the code under WM_CLOSE

case WM_CLOSE:
            //if the user hits [X] to close the window just hide it instead of destroy it!
            ShowWindow(hwnd, SW_HIDE);
            RelocateWindow(250, 200);
            break;

this is the line which hides the window:

ShowWindow(hwnd, SW_HIDE);

So you could use either one, both will call ShowWindow either directly or indirectly it doesn't matter :P

So modify the code like so, and you'll result in a dll like this:

http://www.mediafire.com/file/a4lirhmzmdy/ModLF2_GOOD.zip

test it out :P i think that's how you wanted it. I made no modifications to your exe only the dll!

Link to post
Share on other sites

Thanks for all the help! It's working great.

Now I'm having problems with strings... I was going to do all the string manipulation inside the lf2.exe, but I figured since I'm already using a dll it'd probably be better to do it there.

Sadly c++ doesn't play nice with strings like java ( or c#).

In java I could probably do :

            {
                GetWindowTextA(hModName, ModName, 260);
                *(BYTE*)0x459F78 = 0x00;
                String Load = "\\mods\" + ModName "\\cfg.txt";
                ShowWindow(hwnd, SW_HIDE);
            }

Now I've been trying to do this for ages in c++ with no success.

I tried all these weird things with buffers and sprintf (I'm guessing I was creating an array of chars to hold a string), that failed horribly.

Then I tried to use #include <string> , which I'm guessing is the class that deals with strings in c++ and tries to make it easier. I did get the program to compile but it would just crash when it got to the part where it had to manipulate the string.

Hopefully this is some simple thing that I'm missing, since when I was reading up on GetWindowTextA I saw it returned the length of the string or something... Really confused me.

Help anyone!

Link to post
Share on other sites
Thanks for all the help! It's working great.

Now I'm having problems with strings... I was going to do all the string manipulation inside the lf2.exe, but I figured since I'm already using a dll it'd probably be better to do it there.

Sadly c++ doesn't play nice with strings like java ( or c#).

In java I could probably do :

            {
                GetWindowTextA(hModName, ModName, 260);
                *(BYTE*)0x459F78 = 0x00;
                String Load = "\\mods\" + ModName "\\cfg.txt";
                ShowWindow(hwnd, SW_HIDE);
            }

Now I've been trying to do this for ages in c++ with no success.

I tried all these weird things with buffers and sprintf (I'm guessing I was creating an array of chars to hold a string), that failed horribly.

Then I tried to use #include <string> , which I'm guessing is the class that deals with strings in c++ and tries to make it easier. I did get the program to compile but it would just crash when it got to the part where it had to manipulate the string.

Hopefully this is some simple thing that I'm missing, since when I was reading up on GetWindowTextA I saw it returned the length of the string or something... Really confused me.

Help anyone!

Well you could use the string class, but you don't have to!

what you could do is either use strcat to connect the strings together into 1 string! or you could use sprintf to format the string the way you'd want it! sprintf is the better method! I use sprintf all the time its a very useful function!

Basically it formats data(integers, floating point variables, strings, etc) into a string...

%s means string, %i means integer, %f means float...

heres a reference: http://www.cplusplus.com/reference/clibrar...io/sprintf.html

you should be able to figure out how the function works!

Here's an example app I made which demonstrates its usage...

http://www.mediafire.com/file/rmn4u10jzay/...inipulation.zip

You type something when it prompts you for a mod name, then it formats it into the string using sprintf, and also does the second way of attaching the strings with strcat.

StringFormat.png

#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;

char* ModName = new char[260];
char* output = new char[260];
char* output2 = new char[260];

int main()
{
    SetConsoleTitleA("C++ String Formatting Example");
    system("color 0A");

    printf("Enter Mod Name: ");
    gets(ModName);

    //sprintf formats different types of data into a null terminated c string
    //%s means you want to format a string in there, %i means format an integer, etc...
    //sprintf is for any type of app, it stores the output in a string :P
    sprintf(output, "\\mods\\%s\\cfg.txt", ModName);

    //printf is for console apps writing to the console window
    //printf("Formatted Path: \\mods\\%s\\cfg.txt", ModName);

    printf("\n\nFormatted Path: %s\n\n", output);


    //strcat attaches the second string at the end of the first string

    //start out with something in the string like so...
    strcpy(output2, "\\mods\\");
    //now attach the ModName
    strcat(output2, ModName);
    //and attach the last part
    strcat(output2, "\\cfg.txt");
    

    printf("Formatted Path 2nd: %s\n\n", output2);


    printf("\n\nAs you can see, both methods result in the same final string;)\n");
    system("pause");

    delete[] ModName;
    delete[] output;
    delete[] output2;
    return 0;
}

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...