Massassi Forums Logo

This is the static archive of the Massassi Forums. The forums are closed indefinitely. Thanks for all the memories!

You can also download Super Old Archived Message Boards from when Massassi first started.

"View" counts are as of the day the forums were archived, and will no longer increase.

ForumsShowcase → JK Injector screenshot
JK Injector screenshot
2007-12-12, 9:01 PM #1
[http://a189.ac-images.myspacecdn.com/images01/36/l_ce2e870468cc576806835b8d5bfac294.jpg]

anyone want code? i dont give a crap at this stage

email dpeterson@viztek.net


-jk.exe not modified
-procedurally generates x86 assembly functions in JK's virtual space
-run-time injection of code / eg. hijacking jk's process

-experimental work with supplanting pieces of executable code; overwriting functionality while process is active
-experimental work with hijacking directdraw interface for custom gui overlays


on another note:
i cancelled my dedicated server but i still have the files that were stored on the respository for the 'JKUP' project most recently headed by Zeq; this includes the disassembler software and the JK project with several people's hard work identifying specific functions and components inside the jk engine. my additions involved DirectDraw and DirectShow involvement
[ B A H ]
Bad *** by nature,
Hackers by choice
2007-12-13, 12:36 PM #2
sounds complicated.. whats it do?
"Nulla tenaci invia est via"
2007-12-13, 12:37 PM #3
it's for h4><0r|ng n3wbz.

obviously.
If you choose not to decide, you still have made a choice.

Lassev: I guess there was something captivating in savagery, because I liked it.
2007-12-13, 1:22 PM #4
lol..

well I didn't ask what it's for, but what it does
"Nulla tenaci invia est via"
2007-12-13, 1:40 PM #5
oh.

i dunno.
If you choose not to decide, you still have made a choice.

Lassev: I guess there was something captivating in savagery, because I liked it.
2007-12-13, 2:48 PM #6
Well, that screen shot is of adding a new cog verb... so that's apparantly one of the things you can do ;) Oh, and he mentioned not actually editing the exe, so it sounds like it's hacking the running process and "intercepting" the new verb call. Interesting.
Sam: "Sir we can't call it 'The Enterprise'"
Jack: "Why not!"
2007-12-13, 4:02 PM #7
SG you a smart one :D
[ B A H ]
Bad *** by nature,
Hackers by choice
2007-12-13, 4:28 PM #8
the other part i mentioned is early work on hijacking directdraw interfaces. all you need to do is find somewhere a static pointer to something, and from there you can find what really matters.

first goal was to be able to add a custom HUD to the game

second goal was to rewrite the particle effect drawing system so the goddamn thing supports actual alpha-blended sprites with an additive blending mode. 'splosions and sabers and fire would look rather nice then. and smoke and really anything else.


the 'hijacker' architecture is designed as such to achieve these goals:
1) no modified jk.exe
2) run-time injection and complete cleanup on exit. in other words, you'd be able to load or unload the modifications whilst playing the damn game, several times if you wanted. "supplant and reconstitute"

Code:
// writes data into any protected address. returns unique identifier that can be used
// with reconstitute() to restore data to original state.





this is the 'jacker' class declaration. this is the DLL that is loaded into JK's process by the 'injector'. other DLLs can be loaded from this, meaning any infinite number of extra third-party modules, with one injection app; which is open source if somebody asks for it
Code:
class CJKJacker
{
private:
	// singleton ****
	static CJKJacker *s_pInstance;
	CJKJacker(const CJKJacker &) {  }
	CJKJacker &operator =(const CJKJacker &) { return (*this); }
	CJKJacker() { nullify(); }
	virtual ~CJKJacker() { shutdown(); }

	HMODULE m_hInstance;
	HWND m_hJKWnd;
	WNDPROC m_pJKWndProc;
	OUTTARGET m_outTarget;
	bool m_bRunning;
	HWND m_hLastSenderWnd;

	map<int, SUPPLANTATION*> m_supplantations;

	static LRESULT CALLBACK _wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	LRESULT wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

	void nullify();

	// return true if nID is recognized
	bool onReceiveData(int nID, void *pData, int nDataBytes);


public:
	bool init(HMODULE hInstance, bool bWaitForOutTarget=true);
	void shutdown();

	void process(float fDT);

	void quit();
	bool isRunning() { return m_bRunning; }

	// sends data to last sender. returns false if there was
	// no last sender, or if the last sender did not recognize
	// the data.
	bool sendData(int nID, void *pData=0, int nDataBytes=0);

	void out(const char *szText, ...);
	bool hasOutTarget() { return (m_outTarget.target != OUTTARGET::NONE); }

	inline IDirectDraw *getDirectDraw();
	inline IDirectDrawSurface *getBackbuffer();
	inline IDirectDrawSurface *getFrontbuffer();

	// registers a cog command. the declaration is used to procedurally generate a callback that will
	// automate cog stack interaction. you must be sure that the string declaration corresponds exactly
	// to the actual function declaration.
	//
	// note that the string declaration uses precisely the same keywords as seen in the cog language.
	//
	// example:
	//    int GetNearestThing(CVector3 position, float maxRange);
	//
	//    JACK->registerCommand(GetNearestThing, "int getnearestthing(vector, flex)");
	void registerCommand(void *pCommand, const char *szDeclaration);

	// used internally by registerCommand, but may be used to arbitrarily parse a declaration.
	// if false is returned, the parsing was a failure and the data in pCmdDecl is undefined.
	bool parseCommandDeclaration(const char *szDeclaration, COMMANDDECLARATION *pCmdDecl);

	// writes data into any protected address. returns unique identifier that can be used
	// with reconstitute() to restore data to original state.
	//
	// supplantations may not overlap. in other words, supplanting at address 0x00100000
	// with a size of 16 bytes, then supplanting at any address between 0x00100000 and
	// 0x0010000F at any size will cause the second supplantation to fail.
	//
	// after reconstitution, the region may be supplanted again.
	//
	// returns -1 on failure
	int supplant(void *pAddress, void *pData, int nDataBytes);

	// if pAddress occurs within the region of any current supplantations, the supplantationID
	// is returned. returns -1 if pAddress is not currently supplanted.
	int getSupplantationAtAddress(void *pAddress);

	// restores original data for specified supplantation. the specified ID
	// becomes invalid after this operation completes.
	void reconstitute(int nSupplantationID);

	// restores all original data. this is called automatically by shutdown
	void reconstituteAll();

	// more singleton ****
	static CJKJacker *getInstance() { if(s_pInstance==0) s_pInstance = new CJKJacker; return s_pInstance; }
	static void deleteInstance() { if(s_pInstance != 0) { delete s_pInstance; s_pInstance = 0; } }
};
[ B A H ]
Bad *** by nature,
Hackers by choice
2007-12-13, 4:45 PM #9
actually screw it, im going to make this an SDK and whoever knows a little C can mess with it and write some custom cog functions
[ B A H ]
Bad *** by nature,
Hackers by choice
2007-12-13, 5:28 PM #10
truly awesomeness

would this allow someone in the future to make JK run better with say, one million visible adjoins? that's a concern I have for level design. maybe even a better equipped lighting system and 3do system
"Nulla tenaci invia est via"
2007-12-13, 5:32 PM #11
Awesome. Pure awesome. :awesome:
And when the moment is right, I'm gonna fly a kite.
2007-12-13, 5:34 PM #12
Just imagine if you had made this eight years ago. :)
"it is time to get a credit card to complete my financial independance" — Tibby, Aug. 2009
2007-12-13, 5:36 PM #13
with our pentium 2's and 128mb of memory it probably wouldn't even run lol
"Nulla tenaci invia est via"
2007-12-13, 5:42 PM #14
pfft.. Pentium 2 with 128 MB RAM?!?!

lucky.

I ran JK for several years on a Pentium 1 166mhz, with 32 MB of RAM... (or was it 16).
If you choose not to decide, you still have made a choice.

Lassev: I guess there was something captivating in savagery, because I liked it.
2007-12-13, 8:37 PM #15
well I was thinking y2k

hell in 98' I was playing JK on a p1 200mhz, 64mb ram, voodoo3 16mb pci.. I was so amazed at the accelerated graphics!
"Nulla tenaci invia est via"
2007-12-14, 7:21 PM #16
Originally posted by Z@NARDI:
with our pentium 2's and 128mb of memory it probably wouldn't even run lol


it would, without any problems. unless people started getting nuts with the mods, trying to do all sorts of crap as a background task.

its all native code, loaded into jk's process. as far as jedi knight is concerned, its just calling an extra function here and there. even on a pentium POS with ~notmuch RAM, your cpu wouldn't give a rats ***. might drop you a tenth of a fps at most, not enough to change a whole-integer fps display, by even 1.

unless of course some crazy ******* starts hacking it up and rewriting the particle system. which i would commend them for, nobody has found where all that is in the disassembler :)
[ B A H ]
Bad *** by nature,
Hackers by choice
2007-12-14, 10:28 PM #17
I was so sad though, I remember a while back you guys gave me that disassembler and I was mucking around, then I lost it... I mean seriously, how do you lose something on your hard drive?!? It just vanished, and I don't recall uninstalling it. Just poof.

So this is where I ask for another copy :D please :)

And I for one would love messing with the open source c code, see what there is to change.
Sam: "Sir we can't call it 'The Enterprise'"
Jack: "Why not!"
2007-12-15, 7:28 AM #18
the injection code is in c++, there's not much that needs to be changed. i need to integrate a solution for loading/managing 3rd party modules, which are the mods (DLLs)


complete potential code for a sample mod:
Code:
#include "../JKJacker/JKJacker.h"
#include "../common/Vector3.h"

// so we can use the DirectDraw stuff for GetScreenWidth/GetScreenHeight.
// not required if not using DirectDraw interfaces
#pragma comment(lib, "ddraw.lib")

extern "C" {

int __cdecl GetScreenWidth()
{
	IDirectDrawSurface *pScreen = JACK->getFrontbuffer();
	if(pScreen == 0)
		return -1;

	// now we're making DirectDraw calls
	DDSURFACEDESC desc;
	ZeroMemory(&desc, sizeof(DDSURFACEDESC));
	desc.dwSize = sizeof(DDSURFACEDESC);
	desc.dwFlags = DDSD_WIDTH;
	pScreen->GetSurfaceDesc(&desc);

	// return the screen width back to the script
	return desc.dwWidth;
}

int __cdecl GetScreenHeight()
{
	IDirectDrawSurface *pScreen = JACK->getFrontbuffer();
	if(pScreen == 0)
		return -1;

	// now we're making DirectDraw calls
	DDSURFACEDESC desc;
	ZeroMemory(&desc, sizeof(DDSURFACEDESC));
	desc.dwSize = sizeof(DDSURFACEDESC);
	desc.dwFlags = DDSD_HEIGHT;
	pScreen->GetSurfaceDesc(&desc);

	// return the screen height back to the script
	return desc.dwHeight;
}


// exported function:  called by jacker so we know who this mod is
const char *GetModName()
{
	return "Strike's Sample Mod";
}

// exported function:  called by jacker when the mod is loaded
void __cdecl OnInit()
{
	// do initialization here
	JACK->registerCommand(GetScreenWidth, "int GetScreenWidth()");
	JACK->registerCommand(GetScreenHeight, "int GetScreenHeight()");
}

// exported function:  called by jacker when the mod is unloaded
void __cdecl OnShutdown()
{

}

// exported function:  called by jacker constantly when active,  from jacker's thread.
// fDT is the time elapsed, in seconds, from being called last
void __cdecl OnProcess(float fDT)
{

}

} /* !extern "C" */
[ B A H ]
Bad *** by nature,
Hackers by choice
2007-12-16, 8:55 AM #19
amazing, but why weren't all you crazy hacker dudes around in '99?
Dreams of a dreamer from afar to a fardreamer.
2007-12-16, 10:29 AM #20
i was bro

jk is what got me into this crap :v:


procedural code generation.. definition for CJKJacker::registerCommand
Code:
void CJKJacker::registerCommand(void *pCommand, const char *szDeclaration)
{
	if(pCommand == 0 || szDeclaration == 0)
		return;

	out("%s", szDeclaration);

	// parse declaration
	COMMANDDECLARATION cmd;
	if(!parseCommandDeclaration(szDeclaration, &cmd))
		return;

	/////////////////   JKEXT GETPARAM/SETRETURN -0x290

	// predetermine some **** about returning values
	unsigned long setretfunc = 0;		// address of 'set return value' function, or 0 if not applicable
	int retbytes = 0;					// must set to struct size for commands that return a struct, or 0 if not applicable
	bool returnsStruct = false;
	switch(cmd.ret)
	{
	case VAL_INT:
		setretfunc = 0x004E3340;
		break;

	case VAL_FLEX:
		setretfunc = 0x004E33C0;
		retbytes = sizeof(float);
		break;

	case VAL_VECTOR:
		setretfunc = 0x004E3450;
		retbytes = sizeof(CVector3);
		returnsStruct = true;
		break;

	case VAL_ANY:
		setretfunc = 0x004E32D0;
		retbytes = sizeof(ANY);
		returnsStruct = true;
		break;
	}


	PROC_BEGIN
		//------------------------------------------------------------------------------------------------
		//                                          PROC ENTRY
		//------------------------------------------------------------------------------------------------
		PROC_APPEND_BEGIN
			PUSHREG32(EBP)
			MOV_EBP_ESP
		PROC_APPEND_END


		// make space for return value struct if applicable
		if(retbytes)
			PROC_APPEND_BEGIN
				SUB8(ESP, retbytes)
			PROC_APPEND_END


		PROC_APPEND_BEGIN
			PUSHREG32(ESI)
			PUSHREG32(EDX)
		PROC_APPEND_END

		// retrieve and push params  (reverse order as passed)
		int parambytes = 0;
		for(int x=cmd.numParams-1; x >= 0; x--)
		{
			switch(cmd.params[x])
			{
			case VAL_INT:
				PROC_APPEND_BEGIN
					MOV_EDX_EBP_I8(8)
					PUSHREG32(EDX)
					MOV32(ESI, 0x004E25C0)
					CALL_ESI
					ADD8(ESP, 4)
					PUSHREG32(EAX)
				PROC_APPEND_END
				parambytes += 4;
				break;

			case VAL_FLEX:
				PROC_APPEND_BEGIN
					MOV_EDX_EBP_I8(8)
					PUSHREG32(EDX)
					MOV32(ESI, 0x004E24F0)
					CALL_ESI
					FSTP_ESP
				PROC_APPEND_END
				parambytes += 4;
				break;

			case VAL_VECTOR:
				PROC_APPEND_BEGIN
					SUB8(ESP, sizeof(CVector3))
					LEA_EAX_ESP_I8(0)
					PUSHREG32(EAX)
					MOV_EDX_EBP_I8(8)
					PUSHREG32(EDX)
					MOV32(ESI, 0x004E26E0)
					CALL_ESI
					ADD8(ESP, 8)
				PROC_APPEND_END
				parambytes += sizeof(CVector3);
				break;
			}
		}

		// push return value ptr if applicable
		if(returnsStruct)
		{
			PROC_APPEND_BEGIN
				LEA_EAX_EBP_I8(-retbytes)
				PUSHREG32(EAX)
			PROC_APPEND_END
			parambytes += 4;
		}


		PROC_APPEND_BEGIN
			MOV32(ESI, (__int64)pCommand)
			CALL_ESI
		PROC_APPEND_END


		// pop params if applicable
		if(parambytes)
			PROC_APPEND_BEGIN
				ADD8(ESP, parambytes)
			PROC_APPEND_END


		// special case for floats (return value passed differently)
		if(cmd.ret == VAL_FLEX)
			PROC_APPEND_BEGIN
				FSTP_EBP_I8(-retbytes)
				MOV_EAX_EBP_I8(-retbytes)
			PROC_APPEND_END


		// set return value if appliable
		if(setretfunc)
			PROC_APPEND_BEGIN
				PUSHREG32(EAX)
				MOV_EDX_EBP_I8(8)
				PUSHREG32(EDX)
				MOV32(ESI, setretfunc)
				CALL_ESI
				ADD8(ESP, 8)
			PROC_APPEND_END


		PROC_APPEND_BEGIN
			POPREG32(EDX)
			POPREG32(ESI)
		PROC_APPEND_END


		// pop return value reservation if applicable
		if(retbytes)
			PROC_APPEND_BEGIN
				ADD8(ESP, retbytes)
			PROC_APPEND_END


		PROC_APPEND_BEGIN
			POPREG32(EBP)
			RETN
		PROC_APPEND_END
		//------------------------------------------------------------------------------------------------
		//                                          PROC EXIT
		//------------------------------------------------------------------------------------------------


		// make sure we assign executable privileges to minimize access violation risk
		void *proc = VirtualAlloc(0, PROC_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		VirtualLock(proc, PROC_SIZE);
		memcpy(proc, PROC_BUFFER, PROC_SIZE);
		VirtualUnlock(proc, PROC_SIZE);

		out("gen proc %d:%X", PROC_SIZE, proc);

		// register with cog environment
		((void(*)(long,long,long))0x004E0700)( *(long*)0x008B5428, (long)(__int64)proc, (long)(__int64)cmd.name );
	PROC_END
}



x86 opcodes and the magic behind the PROC calls (macros)
Code:
/*
	DCP07

	for procedural code generation

*/

#define PROC_BEGIN										\
	{													\
		vector<unsigned char> _proc;

#define PROC_APPEND_BEGIN								\
	{													\
		unsigned char _dat[] = {

#define PROC_APPEND_END									\
		};												\
		_proc.resize(_proc.size()+sizeof(_dat));		\
		memcpy(&_proc[_proc.size()-sizeof(_dat)],		\
		_dat, sizeof(_dat));							\
	}

#define PROC_SIZE										\
	((int)_proc.size())

#define PROC_BUFFER										\
	((void*)&_proc[0])

#define PROC_END										\
		_proc.clear();									\
	}


enum { EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI };

#define NOP						0x90,

#define CONSTANT8(n8)			(unsigned char)(n8),
#define CONSTANT32(n32)			(unsigned char)(((unsigned long)(n32))&0xFF), (unsigned char)((((unsigned long)(n32))>>8)&0xFF), (unsigned char)((((unsigned long)(n32))>>16)&0xFF), (unsigned char)(((unsigned long)(n32))>>24),

#define PUSHREG32(r32)			(0x50+(r32)),
#define POPREG32(r32)			(0x58+(r32)),

#define PUSH32(n32)				0x68, CONSTANT32(n32)

#define MOV_EBP_ESP				0x8B, 0xEC,
#define MOV_ESP_EBP				0x8B, 0xE5,

#define XOR_EAX_EAX				0x33, 0xC0,

#define INC_EAX					0x40,

#define MOV32(r32, n32)			(0xB8+(r32)), CONSTANT32(n32)

// FSTP DWORD PTR SS:[EBP]
#define FSTP_EBP_I8(n8)			0xD9, 0x5D, CONSTANT8(n8)

// FSTP DWORD PTR SS:[ESP]
#define FSTP_ESP				0xD9, 0x1C, 0x24,

// MOV EDX,DWORD PTR SS:[EBP+n]
#define MOV_EDX_EBP_I8(n8)		0x8B, 0x55, CONSTANT8(n8)

// MOV EAX,DWORD PTR SS:[EBP+n]
#define MOV_EAX_EBP_I8(n8)		0x8B, 0x45, CONSTANT8(n8)

// MOV EAX,DWORD PTR SS:[ESP+n]
#define MOV_EAX_ESP_I8(n8)		0x8B, 0x44, 0x24, CONSTANT8(n8)

// LEA EAX,DWORD PTR SS:[EBP+n]
#define LEA_EAX_EBP_I8(n8)		0x8D, 0x45, CONSTANT8(n8)

// LEA ECX,DWORD PTR SS:[EBP+n]
#define LEA_ECX_EBP_I8(n8)		0x8D, 0x4D, CONSTANT8(n8)

// LEA EAX,DWORD PTR SS:[ESP+n]
#define LEA_EAX_ESP_I8(n8)		0x8D, 0x44, 0x24, CONSTANT8(n8)

// LEA EAX,DWORD PTR SS:[EBP]
#define LEA_EAX_EBP				0x8D, 0x45, 0xE0,

#define ADD8(r32, n8)			0x83, (0xC0+(r32)), CONSTANT8(n8)
#define ADD32(r32, n32)			0x81, (0xC0+(r32)), CONSTANT32(n32)

#define SUB8(r32, n8)			0x83, (0xE8+(r32)), CONSTANT8(n8)
#define SUB32(r32, n32)			0x81, (0xE8+(r32)), CONSTANT32(n32)

#define CALL_ESI				0xFF, 0xD6,

#define RETN					0xC3,



there, i just gave it all to you. theres not much need to mess with the jacker. that part might stay on my hd

xD hence SDK wip
[ B A H ]
Bad *** by nature,
Hackers by choice
2007-12-18, 10:00 AM #21
SG-fan try this:

http://www.cheatengine.org/

Memory scanner, memory viewer, and disassembler. The main dialog is for scanning and applying cheat codes, but there is a second dialog you can pop up for hex editing / disassembly.

↑ Up to the top!