Quote:
Originally Posted by fanste
I tried it over and over again, also with your last none-GUI version, but the Game keeps crashing during the splash-screen (somewhere in "ntdll.dll"). Maybe it is cuz of win7.. but the iSRO-version is working... :(
I hope it will work for me too as soon as you were able to build it with your new framework.
€dit:
it's working now with many many modifications... I had to use a third-party DLL-Injector and apply a little modification to the dll so it will start after it got injected. Not perfect and it still crashes when i inject it before i joined the world (and sometimes ingame). But better than nothing
|
Really weird. I've not had any other reports of people having trouble with the method on various OSs. I develop on Win7 32bit myself and have tested on Win7 x64 in the past and didn't run into any problems. That method was developed and hihgly tested on WinXP for a number of years. In ever got around to running Vista on my desktop, but I did test it for a while on my x64 laptop.
I'm not sure what's going on in your system that causes the crash, sorry!
I have only one code change suggestion to make to you to see if it helps. Make sure to run in Debug mode and Release mode to see if that makes a difference. I am beginning to think release mode might mess up some of the ASM due to optimizations:
Code:
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include "../common/common.h"
#include "DLL.h"
//-------------------------------------------------------------------------
// Global instance handle to this DLL
HMODULE gInstance = NULL;
// Function prototype
void UserOnInject();
void UserOnDeinitialize();
//-------------------------------------------------------------------------
// Main DLL entry point
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReason, LPVOID lpReserved)
{
UNREFERENCED_PARAMETER(lpReserved);
if(ulReason == DLL_PROCESS_ATTACH)
{
gInstance = hModule;
// Do not notify this DLL of thread based events
DisableThreadLibraryCalls(hModule);
}
else if(ulReason == DLL_PROCESS_DETACH)
{
UserOnDeinitialize();
}
return TRUE;
}
// This is the main function that is called when the DLL is injected into the process
extern "C" __declspec(dllexport) void OnInject(DWORD address, LPDWORD bytes)
{
// Restore the original bytes at the OEP
DWORD wrote = 0;
WriteProcessMemory(GetCurrentProcess(), UlongToPtr(address), bytes, 6, &wrote);
// Call our user function to keep this function clean
UserOnInject();
}
//-------------------------------------------------------------------------
namespace CC_ExtractSentPacket
{
DWORD currentOpcode;
LPBYTE currentBuffer;
DWORD currentSize;
void OnProcessDataStart()
{
printf("[C->S]%X\n", (WORD)currentOpcode);
}
void ProcessData()
{
for(DWORD x = 0; x < currentSize; ++x)
{
printf("%.2X ", currentBuffer[x]);
if((x+1)%16==0)
printf("\n");
}
printf("\n");
}
void OnProcessDataEnd()
{
printf("\n");
}
void EnableParseHook();
void DisableParseHook();
DWORD codecave_SetOpcode_ReturnAddress = 0;
__declspec(naked) void codecave_SetOpcode()
{
__asm pop codecave_SetOpcode_ReturnAddress
__asm MOV AX,WORD PTR SS:[ESP + 0x04] // Original code
__asm mov currentOpcode, eax
__asm pushad
EnableParseHook(); // Start hooking writes
__asm popad
__asm push codecave_SetOpcode_ReturnAddress
__asm ret
}
DWORD codecave_WriteBytes_ReturnAddress = 0;
__declspec(naked) void codecave_WriteBytes()
{
__asm pop codecave_WriteBytes_ReturnAddress
__asm mov currentBuffer, eax
__asm mov currentSize, ebp
__asm pushad
ProcessData();
__asm popad
// Even though this comes first, we will use EBX and then fix it up
// afterwards. This is ok since ECX is not disturbed.
__asm MOV EBX, ECX
// This line seems to give the client problems when compiled in VS,
// so we have to rewrite it a little. This might be one of the hardest
// things to figure out if you were doing this yourself and not
// too experienced.
__asm MOV DWORD PTR SS:[ESP + 0x10], EAX
/*__asm
{
mov ebx, esp
add ebx, 0x10
mov [ebx], eax
}
// Now set our EBX value to what it should be
__asm MOV EBX, ECX*/
__asm push codecave_WriteBytes_ReturnAddress
__asm ret
}
DWORD codecave_PostProcessPacket1_ReturnAddress;
__declspec(naked) void codecave_PostProcessPacket1()
{
__asm pop codecave_PostProcessPacket1_ReturnAddress
__asm pushad
DisableParseHook();
OnProcessDataEnd();
__asm popad
// We choose this line because it is the easiest to codecave and won't likely change
__asm MOV EAX, 0x1008 // Remember #s have to be in HEX! 1008 != 0x1008
__asm push codecave_PostProcessPacket1_ReturnAddress
__asm ret
}
void EnableParseHook()
{
// A little trick I came up with to filter out the packets received
// that make use of this functionality. Not sure if it'll always work,
// but it "should" since the higher 4 bytes of any C->S packet in the
// executable will be 0 since they are hard coded into the client!
DWORD result = currentOpcode & 0xFFFF0000;
//printf("Result = %i\n", result); // Debugging
if(result == 0)
{
// Let the user know we have an new packet being built
OnProcessDataStart();
// Hook the byte writing function
edx::CreateCodeCave(CC_ExtractSentPacket_Address_1, 6, codecave_WriteBytes);
// Hook the post build processing function
edx::CreateCodeCave(CC_ExtractSentPacket_Address_2, 5, codecave_PostProcessPacket1);
}
}
void DisableParseHook()
{
// Restore the byte writing function code
static BYTE patch1[] = {0x8B, 0xD9, 0x89, 0x44, 0x24, 0x10};
edx::WriteBytes(CC_ExtractSentPacket_Address_1, patch1, 6);
// Restore the post build processing function code
static BYTE patch2[] = {0xB8, 0x08, 0x10, 0x00, 0x00};
edx::WriteBytes(CC_ExtractSentPacket_Address_2, patch2, 5);
}
void Setup()
{
edx::CreateCodeCave(CC_ExtractSentPacket_Address, 5, codecave_SetOpcode);
}
}
//-------------------------------------------------------------------------
namespace CC_ExtractPacket
{
DWORD currentOpcode;
LPBYTE currentBuffer;
DWORD currentSize;
void * packetPtr;
DWORD lastAddr = 0;
void OnProcessDataStart()
{
printf("[S->C]%X\n", (WORD)currentOpcode);
}
void ProcessData()
{
for(DWORD x = 0; x < currentSize; ++x)
{
printf("%.2X ", currentBuffer[x]);
if((x+1)%16==0)
printf("\n");
}
printf("\n");
}
void OnProcessDataEnd()
{
printf("\n");
}
void ProcessPacket()
{
LPBYTE lpBuffer = (LPBYTE)packetPtr;
DWORD packetData = *(LPDWORD)(lpBuffer + 0x18 - 4);
currentOpcode = *((LPWORD)(lpBuffer + 0x18));
WORD packetLength = *((LPWORD)(lpBuffer + 0x18 - 16));
if(lastAddr == packetData)
{
}
else
{
lastAddr = packetData;
OnProcessDataStart();
}
}
DWORD codecave_ReadBytes_ReturnAddress = 0;
__declspec(naked) void codecave_ReadBytes()
{
__asm pop codecave_ReadBytes_ReturnAddress
__asm mov currentBuffer, eax
__asm mov currentSize, ebx
__asm pushad
ProcessData();
__asm popad
// Emulate the rest of the function since our codecave overlaps it all
__asm POP ESI
__asm MOV EAX,EBX
__asm POP EBX
__asm RET 8
}
void EnableParseHook()
{
edx::CreateCodeCave(CC_ExtractPacket_Address_2, 7, codecave_ReadBytes);
}
void DisableParseHook()
{
OnProcessDataEnd();
static BYTE patch[] = {0x5E, 0x8B, 0xC3, 0x5B, 0xC2, 0x08, 0x00};
edx::WriteBytes(CC_ExtractPacket_Address_2, patch, 7);
}
DWORD codecave_HookPacketProcess_ReturnAddress;
__declspec(naked) void codecave_HookPacketProcess()
{
__asm pop codecave_HookPacketProcess_ReturnAddress
__asm mov packetPtr, ebx
__asm pushad
ProcessPacket();
EnableParseHook();
__asm popad
__asm PUSH EBX
__asm CALL NEAR EAX
__asm CMP EAX,1
__asm pushad
DisableParseHook();
__asm popad
__asm push codecave_HookPacketProcess_ReturnAddress
__asm ret
}
void Setup()
{
edx::CreateCodeCave(CC_ExtractPacket_Address_1, 6, codecave_HookPacketProcess);
}
}
//-------------------------------------------------------------------------
// The function where we place all our logic
void UserOnInject()
{
// Create a debugging console
edx::CreateConsole("edxAnalyzer Debugging Console");
// Mutex for the launcher, no patches required to start Silkroad now
CreateMutexA(0, 0, "Silkroad Online Launcher");
CreateMutexA(0, 0, "Ready");
CC_ExtractSentPacket::Setup();
CC_ExtractPacket::Setup();
}
//-------------------------------------------------------------------------
void UserOnDeinitialize()
{
}
//-------------------------------------------------------------------------
In this code, the changes were:
- Use
Code:
__asm MOV EBX, ECX
__asm MOV DWORD PTR SS:[ESP + 0x10], EAX
instead of:
Code:
__asm
{
mov ebx, esp
add ebx, 0x10
mov [ebx], eax
}
// Now set our EBX value to what it should be
__asm MOV EBX, ECX
- Call OnProcessDataStart(); before CreateCodeCave in CC_ExtractSentPacket :: EnableParseHook
- Call OnProcessDataEnd() before WriteBytes in CC_ExtractPacket :: DisableParseHook
The first change should not matter since the ASM is the same. However, on the second and third changes, I noticed those fixed a similar crash I have been experiencing on a different project where I am saving the parsed data into buffers but sometimes I crash right after character login. I am still noticing some crashes which trace back to a Silkroad error, so I'm trying to figure out why that is happening.
I don't know why you'd be the only one to experience that with this code though, but that's my only idea for the situation. If I find anything else, I'll let you know!