PDA

View Full Version : Libcod for windows



Mitch
19th December 2013, 20:04
I am gonna try to port libcod to windows. In the newer windows it is made harder to inject DLL's. But it is possible.

I tested the solution below and it works on windows 8.1.
https://github.com/stephenfewer/ReflectiveDLLInjection


Usage: inject.exe [pid] [dll_file]


My first goal will be overriding the closer function.

Edit: added latest version as attachment
Edit 2: if you are getting a unknown function error, it is caused because the dll is linked to mysql. (copy libmysql.dll from lib/ with your libcod dll)
http://killtube.org/showthread.php?1730-Libcod-for-windows&p=10967&viewfull=1#post10967

Edit 3: It might be that pushing a vector or entity doesn't work. (unverified)

Latest source code: https://github.com/M-itch/libcod_win
CoD2 1.0: http://killtube.org/showthread.php?1730-Libcod-for-windows&p=11117&viewfull=1#post11117
CoD2 1.3: http://killtube.org/showthread.php?1730-Libcod-for-windows&p=8864&viewfull=1#post8864

Mitch
19th December 2013, 22:05
Closer isn't working yet but I can now easily inject the DLL.

Inject console application (needs to be run as administrator)


#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>

void EnableDebugPriv() {
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tkp;

OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken );

LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid );

tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

AdjustTokenPrivileges( hToken, false, &tkp, sizeof( tkp ), NULL, NULL );

CloseHandle( hToken );
}

int main( int, char *[] ) {
PROCESSENTRY32 entry;
entry.dwSize = sizeof( PROCESSENTRY32 );

HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, NULL );

if ( Process32First( snapshot, &entry ) == TRUE ) {
while ( Process32Next( snapshot, &entry ) == TRUE ) {
if ( stricmp( entry.szExeFile, "CoD2MP_s.exe" ) == 0 ) {
EnableDebugPriv();

char dirPath[MAX_PATH];
char fullPath[MAX_PATH];

GetCurrentDirectory( MAX_PATH, dirPath );

snprintf ( fullPath, MAX_PATH, "%s\\libcod_win.dll", dirPath );

HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, entry.th32ProcessID );
LPVOID libAddr = (LPVOID)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "LoadLibraryA" );
LPVOID llParam = (LPVOID)VirtualAllocEx( hProcess, NULL, strlen( fullPath ), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );

WriteProcessMemory( hProcess, llParam, fullPath, strlen( fullPath ), NULL );
CreateRemoteThread( hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)libAddr, llParam, NULL, NULL );
CloseHandle( hProcess );
}
}
}

CloseHandle( snapshot );

return 0;
}

(Credits goes to http://stackoverflow.com/a/873659)

DLL


#include "main.h"

int cdecl_injected_closer()
{
MessageBoxA( NULL, "CLOSER", "libcod", MB_OK );
return 1337;
}

void init()
{
int *addressToCloserPointer = (int *)0x0070955B;
*addressToCloserPointer = (int) cdecl_injected_closer;
}

extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
MessageBoxA( NULL, "[PLUGIN LOADED]", "libcod", MB_OK );
init();
break;

case DLL_PROCESS_DETACH:
// detach from process
break;

case DLL_THREAD_ATTACH:
// attach to thread
break;

case DLL_THREAD_DETACH:
// detach from thread
break;
}
return TRUE; // succesful
}


header


#ifndef __MAIN_H__
#define __MAIN_H__

#include <windows.h>

/* To use this exported function of dll, include this header
* in your project.
*/

#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif


#ifdef __cplusplus
extern "C"
{
#endif

#ifdef __cplusplus
}
#endif

#endif // __MAIN_H__

php
20th December 2013, 14:02
If anyone is looking for libcod CoD 1.5 Windows, have a look at this; https://github.com/riicchhaarrd/MDLL/
OT; Why would you want to make it available for Windows 8(.1), since I doubt servers use that to host.

Mitch
20th December 2013, 16:06
If anyone is looking for libcod CoD 1.5 Windows, have a look at this; https://github.com/riicchhaarrd/MDLL/
OT; Why would you want to make it available for Windows 8(.1), since I doubt servers use that to host.

Because i use 8.1 myself and it is easier to test when it works on the os i use on my laptop.

Edit: and the dll is the same for all windows version, but you need to inject it on 7/8.

I am gonna try to print the start message in the console. (it is less annoying than a popup)

Mitch
26th January 2014, 17:58
I got currently the closer function hooked and i can read parameters from the closer function from the stack. (cod2 1.3)

I cleaned up the code and started merging stuff from libcod.
https://github.com/M-itch/libcod_win

Status:
- Retrieve gsc function parameters: working
- pushStackInt, pushStackString, pushStackFloat, stackPushArray, stackPushArrayLast, pushStackVector: working
- pushStackEntity (get spectatorclient): not working
- mysql support: working
- setvelocity: working
- disableGlobalPlayerCollision: working
- getip, getport: working
- io::print (200): working
- stance: working
- get buttons: untested (likely to work)

kung foo man
1st September 2014, 06:42
I've downloaded the lastest Code from GitHub, build with Code::Blocks 13.12 and injected the .dll with CheatEngine, but for some reason the CoD2 process will just not react anymore (blurred out window, need TaskManager to close it). I played a bit with the code, e.g. in DllMain() I can write exit(123); and it will close the process normally. Com_Printf() isn't printing anything though.

Maybe you had the same problem at some point?

Mitch
1st September 2014, 08:52
Maybe you had the same problem at some point?

I didn't have this problem. But I only tested the extension on 1.3. (I never added the addresses for 1.2 or 1.0)

kung foo man
2nd September 2014, 12:49
Ok, found the error by logging the Com_Printf stuff to a file:




// include/functions.h
#if COD_VERSION == COD2_1_3
static FILE *f = NULL;
//static Com_Printf_t Com_Printf = (Com_Printf_t)0x0431EE0;
static int Com_Printf(const char *format, ...) {
if (f == NULL) {
f = fopen("C:\\libcod.txt", "w+"); // start the Link with +dedicated 1 as Administrator for write permissions
//fclose(f);
}
fprintf(f, "%s", format);
fflush(f);
}
#else


Output:

DllMain()
[PLUGIN LOADED]
DllMain()
DllMain()
Already started!
[THREAD DETACH]
DllMain()
[THREAD DETACH]
DllMain()

Here starts the unloading:

DllMain()
[THREAD DETACH]
DllMain()
[THREAD DETACH]
DllMain()
DllMain()
DllMain()
[PLUGIN UNLOADED]


For some reason the DllMain()/DLL_PROCESS_ATTACH is called twice. Fixed it with a simple static variable:



static int isStarted = 0;
DWORD WINAPI MyThread(LPVOID)
{
if (isStarted) {
Com_Printf("Already started!\n");
return NULL;
}
isStarted = 1;
Com_Printf("[PLUGIN LOADED]\n");
#if COD_VERSION == COD2_1_3
cracking_hook_call(0x46E7BF, (int)Scr_GetCustomFunction);
cracking_hook_call(0x46EA03, (int)Scr_GetCustomMethod);
#endif

return 0;
}


Now it's working fine, but the manual injecting is a bit annoying (because the dedi server will crash because of missing functions on start). Gotta look for some LD_PRELOAD replacement for Windows. :)

Mitch
2nd September 2014, 13:12
Gotta look for some LD_PRELOAD replacement for Windows. :)

Would it work if you replaced a default dll (like mss32.dll) and loaded that dll (different name) inside your own dll?

kung foo man
2nd September 2014, 18:12
I don't know, got another idea, which is working fine now :D

Modified your InjectDLL source, to keep it constantly watching the process list for CoD2 and then waiting till the server is closing. After that, it searches again for the process name. Example:

InjectLibcod.bat


start InjectDLL.exe SERVER.exe libcod2_1_3.dll


The new source of it:

#include <stdio.h>
#define _WIN32_WINNT 0x500
#include <windows.h>
#include <tlhelp32.h>

void EnableDebugPriv();
void CALLBACK WaitOrTimerCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired);
int GetProcessByName(char *name, HANDLE *outProcessHandle, int *outProcessID);
void InjectDLL(HANDLE hProcess, char *name);
void WaitForProcessAndInjectDLL(char *name_process, char *name_dll);
void LoopInjecting();

void EnableDebugPriv() {
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tkp;
OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken );
LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid );
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges( hToken, false, &tkp, sizeof( tkp ), NULL, NULL );
CloseHandle( hToken );
}

void CALLBACK WaitOrTimerCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired) {
//MessageBox(0, "The process has exited.", "INFO", MB_OK);
LoopInjecting();
}

int GetProcessByName(char *name, HANDLE *outProcessHandle, int *outProcessID) {
PROCESSENTRY32 entry;
entry.dwSize = sizeof( PROCESSENTRY32 );
HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, NULL );
HANDLE hProcess;
if ( Process32First( snapshot, &entry ) != TRUE )
return 0;
while (Process32Next( snapshot, &entry ) == TRUE) {
if (stricmp( entry.szExeFile, name) != 0)
continue;
// printf("Found: %s\n", entry.szExeFile);
// PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE
*outProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
*outProcessID = entry.th32ProcessID;
return 1;
}
CloseHandle( snapshot );
return 0;
}

void InjectDLL(HANDLE hProcess, char *name) {
char dirPath[MAX_PATH];
char fullPath[MAX_PATH];
GetCurrentDirectory( MAX_PATH, dirPath );
snprintf ( fullPath, MAX_PATH, "%s\\%s", dirPath, name);
printf("Injecting: %s\n", fullPath);
LPVOID libAddr = (LPVOID)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "LoadLibraryA" );
LPVOID llParam = (LPVOID)VirtualAllocEx( hProcess, NULL, strlen( fullPath ) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
printf("libAddr=%.8p llParam=%.8p\n", libAddr, llParam);
bool written = WriteProcessMemory( hProcess, llParam, fullPath, strlen( fullPath ) + 1, NULL );
HANDLE threadID = CreateRemoteThread( hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)libAddr, llParam, NULL, NULL );
//CloseHandle( hProcess );
printf("Finished injecting DLL success=%d thread #%d\n", written, threadID);
}

void WaitForProcessAndInjectDLL(char *name_process, char *name_dll) {
printf("WaitForProcessAndInjectDLL(process=%s, dll=%s);\n", name_process, name_dll);
HANDLE hProcess;
int processID;
while (1) {
int ret = GetProcessByName(name_process, &hProcess, &processID);
if (ret == 0) {
printf(".");
Sleep(1000);
continue;
}
printf("\nprocessID=%d\n", processID);
InjectDLL(hProcess, name_dll);
HANDLE hNewHandle;
RegisterWaitForSingleObject(&hNewHandle, hProcess, WaitOrTimerCallback, NULL, INFINITE, WT_EXECUTEONLYONCE);
break;
}
}

int argc;
char **argv;
void LoopInjecting() {
// CoD2MP_s.exe
WaitForProcessAndInjectDLL(argv[1], argv[2]); // process, dll
}
int main(int c, char **v) {
argc = c;
argv = v;
if (argc < 2) {
printf("Please provide process-name and dll-name!\nExample: InjectDLL SERVER.exe libcod2_1_3.dll");
getchar();
return 1;
}
EnableDebugPriv();
LoopInjecting();
getchar();
return 0;
}




Download: 743

744

Mitch
11th September 2014, 15:13
Question from a PM

So, I'm very interested on using libcod.

My doubts are:
Where should I run the InjectDLL.exe? And does it work on windows 7?
Does it have MySql functions that will allow me to save player data (ranks)?
If it does have MySql functions, how can I login to the database (I use xampp)?
Do you have a list of functions?


Thanks in advance ;)

InjectDLL.exe works on Windows 8. (place it in the same directory as your cod2 install) + libcod.dll
The windows version of libcod has mysql support.
You can use xampp for your database.
Functions list: http://znation.nl/cod4script/ (not all but most, check https://github.com/M-itch/libcod/blob/new-master/gsc.cpp)

guiismiti
11th September 2014, 17:30
InjectDLL.exe works on Windows 8.

So, no windows 7 support right now?

Thanks for the quick reply

Mitch
11th September 2014, 17:44
So, no windows 7 support right now?

Thanks for the quick reply

No, i meant if it works on Windows 8 then it should also work on Windows 7. (so far i know it hasn't been tested on Windows 7)

guiismiti
12th September 2014, 16:47
Should the size of the binary have changed? It still has 1928 kb.

guiismiti
13th September 2014, 23:20
I mean, this is all I'm getting

759

My game is properly registered.

IzNoGoD
13th September 2014, 23:50
Are you running it as admin? Or uac off? Or win 8.x + uac off + lua mode off?

guiismiti
14th September 2014, 01:04
Running as admin, yes.

Sorry that I'm not giving many details, I just don't have a clue what might be wrong.

serthy
13th December 2014, 11:29
I couldn't get libcod to run on win7 x64 when building it from Mitch's repo with tdm64, gcc4.9.2 and the included C::B project files.
I had to set -fpermissive and disable mysql to compile it, the injector works fine (kung's source).
Using kung's binaries, everything works as it should, however my builds fail with the unknown function script compile error.
Did I miss something?

Mitch
13th December 2014, 15:02
I couldn't get libcod to run on win7 x64 when building it from Mitch's repo with tdm64, gcc4.9.2 and the included C::B project files.
I had to set -fpermissive and disable mysql to compile it, the injector works fine (kung's source).
Using kung's binaries, everything works as it should, however my builds fail with the unknown function script compile error.
Did I miss something?

No idea. I just build my source with CodeBlocks 13.12 using GCC 4.7.1 (mingw32-g++.exe) on Windows 8.1.

serthy
13th December 2014, 21:37
Thank you!
Unfortunately this DLL does not work on my machine either
(when injecting the dll the CoD2 server console throws this unknown function script compile error for not finding a libcod-function)
Maybe its something with the binaries file size (kung: 200kb, yours and my builds: < 50kb)?
Is there something i can do? It rather seems to be beyond my coding-capabilities atm

kung foo man
13th December 2014, 22:39
I just checked what I did actually different in my version and the only relevant change is in main.cpp:



#include "main.h"
#include <stdio.h>
#include "include/functions.h"
#include "include/cracking.h"
#include "include/gsc.h"

DWORD WINAPI MyThread(LPVOID);
DWORD g_threadID;
HMODULE g_hModule;

static int isStarted = 0;
DWORD WINAPI MyThread(LPVOID)
{
if (isStarted) {
Com_Printf("Already started!\n");
return NULL;
}
isStarted = 1;
Com_Printf("[PLUGIN LOADED]\n");
#if COD_VERSION == COD2_1_3
cracking_hook_call(0x46E7BF, (int)Scr_GetCustomFunction);
cracking_hook_call(0x46EA03, (int)Scr_GetCustomMethod);
#endif

return 0;
}

extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
Com_Printf("DllMain()\n");
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
g_hModule = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
CloseHandle(CreateThread(NULL, 0, &MyThread, NULL, 0, &g_threadID));
MyThread(NULL);
break;

case DLL_THREAD_ATTACH:
// attach to thread
break;

case DLL_PROCESS_DETACH:
Com_Printf("[PLUGIN UNLOADED]\n");
FreeLibraryAndExitThread(g_hModule, 0);
break;

case DLL_THREAD_DETACH:
Com_Printf("[THREAD DETACH]\n");
break;
}
return TRUE; // succesful
}


That's were I had all my problems as well: server crashed or just didn't work at all.

Changes in SmartGit:

810

I guess the CloseHandle(CreateThread()) is just not doing anything and could be commented out also. I call MyThread() without threading, since it is just hooking the two functions nonetheless.

When it still doesn't work, check the Com_Printf() to figure out to what point the code actually did something:

File: functions.h


#if COD_VERSION == COD2_1_3
#if 0
static Com_Printf_t Com_Printf = (Com_Printf_t)0x0431EE0;
#else
static FILE *f = NULL;
static int Com_Printf(const char *format, ...) {
if (f == NULL) {
f = fopen("libcod.txt", "a+");
//fclose(f);
}
fprintf(f, "%s", format);
fflush(f);
}
#endif
#else
static Com_Printf_t Com_Printf = (Com_Printf_t)NULL;
#warning Com_Printf_t Com_Printf = NULL;
#endif

Mitch
14th December 2014, 01:21
Thank you!
Unfortunately this DLL does not work on my machine either
(when injecting the dll the CoD2 server console throws this unknown function script compile error for not finding a libcod-function)


It might be because it is linked against the mysql library.
Try to copy libmysql.dll (in lib/) with the libcod dll.

serthy
14th December 2014, 09:19
It might be because it is linked against the mysql library.
Try to copy libmysql.dll (in lib/) with the libcod dll.
Thanks, this did the trick!
I also had to use the -m32 flag in compiler and linker settings to build a 32bit dll (when using TDM-GCC64), now its working :)

Mitch
4th January 2015, 19:01
I added basic support for 1.0. But i haven't tested all the functions. So it might be that some functions don't work yet. Probably the entity and vector return value.

https://github.com/M-itch/libcod_win/commit/a46c856df2e7820df21710714fd9436e4e13b717

I also included kung's injector loop (with a dll check).

Edit: status 1.0

Working
- All param functions are working (string, int, float, vector)
- string, int and float return functions are working
- ip/ping are working

Not working/untested
- Vector, entity and array return functions haven't been tested yet
- All player functions haven't been tested yet (except ip/ping)

Edit 2: https://github.com/M-itch/libcod_win/commit/46d1549c5e7412ffca58349ff22b230f5cd3985f (Added player functions to 1.0, build 2)
Edit 3: https://github.com/M-itch/libcod_win/commit/b23788a7b5aecbf1c66725256401c2f823c9490a (fix vector stack push, build 3)
Edit 3: https://github.com/M-itch/libcod_win/commit/2eaf7df651fd46c1bd9930355cf943c86cfa6651 (IWD download check, build4)

Ni3ls
13th January 2015, 19:52
When i use this, must I still preload it?

EDIT:

827

kung foo man
13th January 2015, 20:14
That's basically "runtime loading", with a possible delay of a second. I think you didn't called your server-binary "sd.exe" (or didn't start yet ^^), otherwise it should be found by the loop and some inject message shoud appear.

Ni3ls
13th January 2015, 20:31
Well when I run the InjectDLL.exe and write

InjectDLL sd.exe libcod2_1_0.dll and press enter it dissappears immediatly. Even if the server is started.
So I modified InjectLibcod.bat with notepad and changed it to the correct files. Then I get that window that doesn't go away. I tried it with server on and off. No result so far. It's a home-server btw

EDIT: Nevermind! Works like a charm. It was the wrong process name

guiismiti
22nd March 2017, 23:41
Not sure if anybody is still having trouble using it on windows 7 x64, but I just did it successfully.
I'm using the .dll files from Mitch's repository and the Inject .exe and .bat from Kung.

<3 libcod

guiismiti
6th April 2017, 14:50
Which compiler do you use?
I'm trying to add missing functions.

kung foo man
6th April 2017, 16:29
https://killtube.org/showthread.php?1730-Libcod-for-windows&p=10962&viewfull=1#post10962


No idea. I just build my source with CodeBlocks 13.12 using GCC 4.7.1 (mingw32-g++.exe) on Windows 8.1.

But investing a bit work, it should work nicely with Visual Studio aswell

67gurkan67
24th December 2017, 18:10
I never know what to do.
Could you describe me in detail? No Video?
''Windows Xp 32 Bit''
Call of Duty 2 v 1.0

1382