Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Samurai's PwnAdventure 3 DLL
#include <Windows.h>
#include <detours.h>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#pragma comment(lib, "detours.lib")
// Classes
class TCPSocket {};
class Player {};
class Actor {};
// Structs
struct Vector3 {
float x, y, z;
};
// Typedefs
typedef bool(__thiscall *SendFunc)(TCPSocket *, const void*, unsigned int);
typedef bool(__thiscall *RecvFunc)(TCPSocket *, void*, unsigned int);
typedef bool(__thiscall *CanJumpFunc)(Player *);
typedef bool(__thiscall *PlayerChatFunc)(Player *, const char *);
typedef void(__thiscall *PlayerFastTravelFunc)(Player *, const char *, const char *);
typedef void(__thiscall *ActorSetPositionFunc)(Actor *, Vector3 *);
// Globals
SendFunc RealSend;
RecvFunc RealRecv;
CanJumpFunc RealCanJump;
PlayerChatFunc RealChat;
PlayerFastTravelFunc PlayerFastTravel;
ActorSetPositionFunc ActorSetPosition;
Player *playerObj = 0;
TCPSocket *clientSock = 0;
std::ofstream DbgLogger;
// Eggs!
Vector3 goldEggs[10] = {
{ -25045.0, 18085.0, 260.0 },
{ -51570.0, -61215.0, 5020.0 },
{ 24512.0, 69682.0, 2659.0 },
{ 60453.0, -17409.0, 2939.0 },
{ 1522.0, 14966.0, 7022.0 },
{ 11604.0, -13131.0, 411.0 },
{ -72667.0, -53567.0, 1645.0 },
{ 48404.0, 28117.0, 704.0 },
{ 65225.0, -5740.0, 4928.0 },
{ -2778.0, -11035.0, 10504.0 }
};
// Known offsets
DWORD TCPSocket_Read_Offset = 0x60950;
DWORD TCPSocket_Write_Offset = 0x60A30;
DWORD Player_CanJump_Offset = 0x51680;
DWORD Player_Chat_Offset = 0x551A0;
DWORD Player_Teleport_Offset = 0x54E50;
DWORD Player_FastTravel_Offset = 0x55AE0;
DWORD Player_PerformFastTravel_Offset = 0x55C10;
DWORD Player_Obj_Offset = 0x97e48;
DWORD Actor_SetPosition_Offset = 0x1C80;
// Thanks to paxdiablo from stackoverflow for the sweet formatting code
// http://stackoverflow.com/questions/7775991/how-to-get-hexdump-of-a-structure-data/7776146#7776146
void LogPacket(char *desc, void *addr, int len) {
int i;
unsigned char buff[17];
unsigned char *pc = (unsigned char*)addr;
FILE* pktLog;
fopen_s(&pktLog, "PwnHaxPkts.txt", "a+");
if (desc != NULL)
fprintf(pktLog, "%s:\n", desc);
// Process every byte in the data.
for (i = 0; i < len; i++) {
// Multiple of 16 means new line (with line offset).
if ((i % 16) == 0) {
// Just don't print ASCII for the zeroth line.
if (i != 0)
fprintf(pktLog, " %s\n", buff);
// Output the offset.
fprintf(pktLog, " %04x ", i);
}
// Now the hex code for the specific character.
fprintf(pktLog, " %02x", pc[i]);
// And store a printable ASCII character for later.
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
buff[i % 16] = '.';
else
buff[i % 16] = pc[i];
buff[(i % 16) + 1] = '\0';
}
// Pad out last line if not exactly 16 characters.
while ((i % 16) != 0) {
fprintf(pktLog, " ");
i++;
}
// And print the final ASCII bit.
fprintf(pktLog, " %s\n", buff);
fclose(pktLog);
}
bool __fastcall HookedSend(TCPSocket *s, int edx, const void* buf, unsigned int len)
{
// Save pointer to TCPSocket for later
if (clientSock == 0) {
clientSock = s;
}
LogPacket("Send()", (void *)buf, len);
return RealSend(s, buf, len);
}
bool __fastcall HookedRecv(TCPSocket *s, int edx, void *buf, unsigned int len)
{
bool retVal;
retVal = RealRecv(s, buf, len);
LogPacket("Recv()", buf, len);
return retVal;
}
bool __fastcall HookedCanJump(Player *p, int edx)
{
return TRUE;
}
void __fastcall HookedChat(Player *p, int edx, const char *text)
{
char buf[256];
sprintf(buf, "PwnHax.dll: Hooked Chat(): player ptr is %p\n", p);
OutputDebugStringA(buf);
if (strcmp(text, "foo") == 0) {
// Just for testing
OutputDebugStringA("PwnHax.dll: Hooked Chat(): got 'foo'\n");
}
else if (strcmp(text, "/cows") == 0) {
OutputDebugStringA("PwnHax.dll: Hooked Chat(): got '/cows'\n");
PlayerFastTravel(p, "Town", "CowLevel");
}
else if (strncmp(text, "/teleport", 9) == 0) {
Vector3 *v;
char *eggName;
OutputDebugStringA("PwnHax.dll: Hooked Chat(): got '/teleport'\n");
// Make a pointer to the egg name
eggName = (char *)text + 10;
// Set our vector to the right egg
// (what a fucking ugly block of code)
if (strcmp(eggName, "egg1") == 0) {
v = &goldEggs[0];
}
else if (strcmp(eggName, "egg2") == 0) {
v = &goldEggs[1];
}
else if (strcmp(eggName, "egg3") == 0) {
v = &goldEggs[2];
}
else if (strcmp(eggName, "egg4") == 0) {
v = &goldEggs[3];
}
else if (strcmp(eggName, "egg5") == 0) {
v = &goldEggs[4];
}
else if (strcmp(eggName, "egg6") == 0) {
v = &goldEggs[5];
}
else if (strcmp(eggName, "egg7") == 0) {
v = &goldEggs[6];
}
else if (strcmp(eggName, "egg8") == 0) {
v = &goldEggs[7];
}
else if (strcmp(eggName, "egg9") == 0) {
v = &goldEggs[8];
}
else if (strcmp(eggName, "egg10") == 0) {
v = &goldEggs[9];
}
else {
sprintf(buf, "PwnHax.dll: Hooked Chat(): unknown teleport location %s\n", eggName);
OutputDebugStringA(buf);
return;
}
// Actor::SetPosition() takes a pointer to the Player's Actor base class. The Player pointer
// passed to this member function is actually to the IPlayer object for the current player.
// From IDA we can deduce that the Actor object comes before the IPlayer object for the player in memory.
// In other words, take the first argument, subtract 0x70 (sizeof(Actor)), and you have a pointer
// to the Actor object you need.
ActorSetPosition((Actor *)(((char *)p) - 0x70), v);
return;
}
RealChat(p, text);
}
void __fastcall HookedPlayerFastTravel(Player *p, int edx, const char *origin, const char *dest)
{
OutputDebugStringA("PwnHax.dll: Hooked Player::FastTravel() called.\n");
// Yet another way to get the CowLevel. This can be disabled since you can just
// type '/cows' in chat, but I'll leave it as an example of another solution for hacking
// FastTravel
if (strcmp(dest, "GoldFarm") == 0) {
PlayerFastTravel(p, origin, "CowLevel");
}
else {
PlayerFastTravel(p, origin, dest);
}
}
// This dummy export is necessary for proper loading of the DLL
extern "C" __declspec(dllexport) void dummy(void)
{
return;
}
BOOL ResolveSymbols(void)
{
HMODULE hLib = GetModuleHandleA("GameLogic.dll");
if (hLib == NULL) {
DbgLogger << "Couldn't locate GameLogic.dll!" << std::endl;
return FALSE;
}
DbgLogger << "Addr of GameLogic.dll: " << hLib << std::endl;
DWORD_PTR realSendAddress = (DWORD_PTR)hLib + TCPSocket_Write_Offset;
RealSend = (SendFunc)realSendAddress;
DbgLogger << "Addr of TCPSocket::Write(): " << (HMODULE)realSendAddress << std::endl;
DWORD_PTR realRecvAddress = (DWORD_PTR)hLib + TCPSocket_Read_Offset;
RealRecv = (RecvFunc)realRecvAddress;
DbgLogger << "Addr of TCPSocket::Read(): " << (HMODULE)realRecvAddress << std::endl;
DWORD_PTR realCanJumpAddress = (DWORD_PTR)hLib + Player_CanJump_Offset;
RealCanJump = (CanJumpFunc)realCanJumpAddress;
DbgLogger << "Addr of Player::CanJump(): " << (HMODULE)realCanJumpAddress << std::endl;
DWORD_PTR realChatAddress = (DWORD_PTR)hLib + Player_Chat_Offset;
RealChat = (PlayerChatFunc)realChatAddress;
DbgLogger << "Addr of Player::Chat(): " << (HMODULE)realChatAddress << std::endl;
DWORD_PTR playerFastTravelAddress = (DWORD_PTR)hLib + Player_FastTravel_Offset;
PlayerFastTravel = (PlayerFastTravelFunc)playerFastTravelAddress;
DbgLogger << "Addr of Player::FastTravel(): " << (HMODULE)playerFastTravelAddress << std::endl;
DWORD_PTR actorSetPositionAddress = (DWORD_PTR)hLib + Actor_SetPosition_Offset;
ActorSetPosition = (ActorSetPositionFunc)actorSetPositionAddress;
DbgLogger << "Addr of Actor::SetPosition(): " << (HMODULE)actorSetPositionAddress << std::endl;
playerObj = (Player *)hLib + Player_Obj_Offset;
DbgLogger << "Addr of IPlayer: " << (HMODULE)playerObj << std::endl;
return TRUE;
}
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
LONG error;
if (DetourIsHelperProcess()) {
return TRUE;
}
DbgLogger.open("PwnHaxDbg.txt", std::ios::out);
DbgLogger << "Logging started!!!" << std::endl;
if (dwReason == DLL_PROCESS_ATTACH) {
if (ResolveSymbols() == FALSE) {
return FALSE;
}
//DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID &)RealSend, HookedSend);
DetourAttach(&(PVOID &)RealRecv, HookedRecv);
DetourAttach(&(PVOID &)RealCanJump, HookedCanJump);
DetourAttach(&(PVOID &)RealChat, HookedChat);
DetourAttach(&(PVOID &)PlayerFastTravel, HookedPlayerFastTravel);
error = DetourTransactionCommit();
if (error == NO_ERROR) {
DbgLogger << "Attached successfully...." << std::endl;
}
else {
DbgLogger << "Failed to attach!!!" << std::endl;
}
}
else if (dwReason == DLL_PROCESS_DETACH) {
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID &)RealSend, HookedSend);
DetourDetach(&(PVOID &)RealRecv, HookedRecv);
DetourDetach(&(PVOID &)RealCanJump, HookedCanJump);
DetourDetach(&(PVOID &)RealChat, HookedChat);
DetourDetach(&(PVOID &)PlayerFastTravel, HookedPlayerFastTravel);
DetourTransactionCommit();
DbgLogger.close();
}
return TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment