I wrote a very simple hack for my Assembly Language class (written in assembly) that redirects the Conquer Online game client's connections. It doesn't change the original ports (I ran into problems of it replacing all port numbers, so I'm saving that for when I create a detouring project), but it does allow you to change the IP address it uses. I've sampled clients 4343 through 587x (or whatever the current client is). I assume it works on all clients. It also works on The Warlords, Eudemons, CrazyTao, and other TQ game clients (though they haven't been fully tested). I've included some of those versions of the hack below.
Here's the source code for the hack (because it's nothing special).
Code:
; --------------------------------------------------------------------------------------------------------- ; Connection Redirect ; --------------------------------------------------------------------------------------------------------- ; This application creates and targets the Conquer Online game process. After the game client has completed ; loading and is available for processing, the application will overwrite the process's inet_addr function. ; By doing so, the client can connect to the private server of the user's choice. ; --------------------------------------------------------------------------------------------------------- ; This directive enables assembly of nonprivileged instructions for the Intel 80386 processor, a 32-bit ; microprocessor introduced by Intel in 1985 which adopted the original implementation of the 8086 ; architecture. It disables assembly of instructions introduced with later processors. It also enables ; 80387 instructions. .386 ; Initializes the program memory model. FLAT memory model is a 32-bit model where memory appears to the ; program as a single contiguous address space. The language type selected for naming conventions and calls ; is the standard calling type. The STDCALL calling convention is a variation on the Pascal calling ; convention in which the callee is responsible for cleaning up the stack, but the parameters are pushed ; onto the stack in right-to-left order, as in the _cdecl calling convention. Registers EAX, ECX, and EDX ; are designated for use within the function. Return values are stored in the EAX register. STDCALL is ; the standard calling convention for the Microsoft Win32 API and for Open Watcom C++. .MODEL FLAT, STDCALL OPTION CASEMAP: NONE ; Assign CASEMAP to properly call Windows API constants and functions. ; When used with .MODEL, .STACK defines a stack segment (with segment name STACK). Tells the assembler to ; reserve 4096 bytes of uninitialized storage for stack variables. The default (if not specified) is ; 1024 bytes. .STACK 4096 ; --------------------------------------------------------------------------------------------------------- ; Project Library Includes ; --------------------------------------------------------------------------------------------------------- ; In MASM32, each include file created by the L2INC.EXE utility has a matching library file. If function ; from a specific library are required, both the include and library file for that library must be included ; in the assembly code. ; --------------------------------------------------------------------------------------------------------- INCLUDE \masm32\include\windows.inc INCLUDE \masm32\include\kernel32.inc INCLUDE \masm32\include\user32.inc INCLUDE \masm32\include\ws2_32.inc INCLUDELIB \masm32\lib\kernel32.lib INCLUDELIB \masm32\lib\user32.lib INCLUDELIB \masm32\lib\ws2_32.lib ; --------------------------------------------------------------------------------------------------------- ; Project Procedure Prototypes ; --------------------------------------------------------------------------------------------------------- CombineStrings PROTO lSourcePtr:DWORD, lDestinationPtr:DWORD, lLength:DWORD ; --------------------------------------------------------------------------------------------------------- .CONST ; Project Constant Definitions: ; --------------------------------------------------------------------------------------------------------- CR EQU 0Dh LF EQU 12h CLIENT EQU "Conquer Online" ; --------------------------------------------------------------------------------------------------------- .DATA ; Local-Scope Variable Definitions: ; --------------------------------------------------------------------------------------------------------- ; This directive starts a near data segment for initialized data. Local-Scope variables for the assembly ; program are defined locally. ; --------------------------------------------------------------------------------------------------------- szCommandLineArguments BYTE " blacknull", 0 ; Command line arguments for starting the process. szModuleName BYTE "WS2_32.dll", 0 ; The module being targeted for memory overwrite. szProcessName BYTE "Conquer.exe", 0 ; The process name for starting the target client. szINetFunctionName BYTE "inet_addr", 0 ; The name of the inet_addr function for redirect. dwErrorCode DWORD 0 ; The result of a called Windows API function. dwModuleAddress DWORD 0 ; The address to the target module. dwINetFunctionAddress DWORD 0 ; The address to the INet function. ; Socket API Configuration: bdWSAStarted BYTE FALSE ; Zero if the WSA hasn't been started up. dwIPAddress DWORD ? ; The IP address used to redirect the client connection. dwWSAVersion DWORD 101h ; Windows Socket API Version 1.1 ; Structure definitions: structSocketData WSADATA <?> ; Windows Socket instance data pointer. structStartupInfo STARTUPINFO <?> ; Start up information for creating the client process. structProcInfo PROCESS_INFORMATION <?> ; Process information for handling the client process. ; Configuration file variable definitions: szConfigFileName BYTE "Launcher.ini", 0 ; The name of the configuration file. szConfigSection BYTE "Redirect", 0 ; The name of the section to read from in the INI file. szConfigIpKey BYTE "IPAddress", 0 ; The key for reading in the IP Address. szConfigDefaultValue BYTE 0 ; The default value for reading in data from the INI file. szConfiguredIpAddress BYTE 35 DUP(0) ; The IP Address read in from the configuration file. ; Environment variable definitions: szWorkingDirectory BYTE 512 DUP(0) ; The path to the current working folder. ; Error Message Box Text: szMessageBoxTitle BYTE CLIENT, " Connection Redirect", 0 szSuccessMessage BYTE "Success", 0 szErrorCurrentDirectory BYTE "Error Code 1: Get Current Directory", CR, "There was an error in getting the current directory of the program. Ensure ", "that your path is less than 512 characters long, and that you have rights ", "in the directory.", 0 szErrorWSANotReady BYTE "Error Code 2: WSA Startup", CR, "The network subsystem is unavailable. The Windows Sockets implementation ", "cannot function at this time because the underlying system it uses to ", "provide network services is currently unavailable.", 0 szErrorWSANotSupported BYTE "Error Code 3: WSA Startup", CR, "The Winsock.dll version requested is out of range. The current Windows ", "Sockets implementation does not support the Windows Sockets specification ", "version requested by the launcher. Check that no old Windows Sockets DLL ", "files are being accessed.", 0 szErrorWSAInProgress BYTE "Error Code 4: WSA Startup", CR, "A blocking operation is currently executing. Windows Sockets only allows ", "a single blocking operation — per-task or thread — to be outstanding, and ", "if any other function call is made (whether or not it references that or ", "any other socket) the function fails.", 0 szErrorWSALimit BYTE "Error Code 5: WSA Startup", CR, "A Windows Sockets implementation may have a limit on the number of ", "applications that can use it simultaneously. Too many processes are using ", "the Windows Socket implementation.", 0 szErrorWSAGeneric BYTE "Error Code 6: WSA Startup", CR, "An unknown error caused the launcher to fail. Try restarting your computer ", "to reset the Windows Socket system implementation.", 0 szErrorIniRead BYTE "Error Code 7: Launcher Configuration", CR, "Please ensure that the Launcher.ini configuration file is in the same ", "directory as your ", CLIENT, " client and the launcher executable.", 0 szErrorInet BYTE "Error Code 8: Invalid IP Address", CR, "Please ensure that the IP address entered in the Launcher.ini ", "configuration file is a valid IP address. Accepted notations are decimal, ", "octal, hexadecimal, and mixed in the form a.b.c.d.", 0 szErrorProcessNotFound BYTE "Error Code 9: Process Not Found", CR, "Please ensure that the ", CLIENT, " client is in the same directory as ", "the launcher executable.", 0 szErrorProcessAuth BYTE "Error Code 10: Access Denied", CR, "The placement of your ", CLIENT, " client has caused the launcher to ", "throw an authentication error. Please restart the launcher with ", "administrative privileges, or move the client to a user owned directory.", 0 szErrorCreateProcess BYTE "Error Code 11: Create Process", CR, "The ", CLIENT, " client could not be started at this time. If this ", "problem continues, please report it to Spirited with the following ", "information: the location of your client, your operating system, and steps ", "you have taken to solve this problem.", 0 szErrorGetWSAModule BYTE "Error Code 12: WSA Module", CR, "There was a problem finding the WSA module in the ", CLIENT, " client. ", "Please restart the launcher and try again. If the problem persists, please ", "report the problem to Spirited for troubleshooting.", 0 szErrorGetINetFunc BYTE "Error Code 13: WSA Function", CR, "There was a problem finding a function from the WSA module in the ", CLIENT, " client. Please restart the launcher and try again. If the problem ", "persists, please report the problem to Spirited for troubleshooting.", 0 szErrorProcessWait BYTE "Error Code 14: Input Wait", CR, "There was a problem waiting for the ", CLIENT, " client to become idle. ", "The client might be unresponsive, or might have been terminated prematurely. ", "Please restart the launcher and try again. If the problem persists, please ", "report the problem to Spirited for troubleshooting.", 0 szErrorMemoryWrite BYTE "Error Code 15: Memory Write", CR, "There was a problem writing instructions to memory. Please ensure that the ", "client is in an accessible location. If not, please restart the launcher ", "with administrative privileges, or move the client to a user owned ", "directory.", 0 ; Instructions to be written: arINetAddrInstructions BYTE 0B8h, 00h, 00h, 00h, 00h, 0C2h, 04h, 00h, 90h, 90h ; B8 00 00 00 00 MOV EAX, Address (DWORD) Address returned in EAX. ; C2 04 00 RET 4 (WORD) Return & pop 4 bytes to ; 90 90 NOP NOP restore stack of arguments. ; --------------------------------------------------------------------------------------------------------- .CODE ; Program Instructions ; --------------------------------------------------------------------------------------------------------- ; The label "start" is the address of the entry point for the assembly program. MASM32 requires this label ; to be included. All procedures in this module must be written between the start and end start labels. ; The CODE directive indicates the start of the code segment. ; --------------------------------------------------------------------------------------------------------- start: ; Get the current working directory and check for errors: INVOKE GetCurrentDirectoryA, SIZEOF szWorkingDirectory, ADDR szWorkingDirectory MOV dwErrorCode, EAX ; Move the error code into the error code variable. CMP dwErrorCode, 0 ; Compare the result of the function to the error code. JE _currentDirectoryError ; Jump to the error code if there was an issue. ; Error check the length of the path: MOV EBX, LENGTHOF szConfigFileName ; Move the length of the file name to EBX. ADD EBX, dwErrorCode ; Add the length of the path and file name. CMP EBX, LENGTHOF szWorkingDirectory ; Compare the length of the path buffer. JG _currentDirectoryError ; Jump to the error code if there was an issue. ; Add a '\' to the end of the string: MOV EDI, OFFSET szWorkingDirectory ; Move the working directory pointer into ESI. ADD EDI, EAX ; Add EAX (the length taken in) to ESI. MOV BYTE PTR[EDI], 5Ch ; Change the character at ESI + EAX to '\'. INC EDI ; Increment EDI. ; Combine the working directory with the configuration file path: INVOKE CombineStrings, OFFSET szConfigFileName, EDI, LENGTHOF szConfigFileName MOV EDX, LENGTHOF szConfiguredIpAddress ; Get the length of the buffer. DEC EDX ; Subtract by one for the null terminator. ; Read in the IP address from the INI file: INVOKE GetPrivateProfileStringA, ADDR szConfigSection, ADDR szConfigIpKey, ADDR szConfigDefaultValue, ADDR szConfiguredIpAddress, EDX, ADDR szWorkingDirectory MOV dwErrorCode, EAX ; Move the error code into the error code variable. CMP dwErrorCode, 0 ; Check if an error occurred. JE _readConfigError ; Jump if an error occurred. ; Start up the Windows Socket API: INVOKE WSAStartup, dwWSAVersion, ADDR structSocketData MOV dwErrorCode, EAX ; Move the error code into the error code variable. CMP dwErrorCode, 0 ; Compare the result of the function to zero. JNE _socketStartupError ; Jump if the start up failed. MOV bdWSAStarted, 1 ; Set the WSA clean up to true. ; Create the IP address DWORD: INVOKE inet_addr, ADDR szConfiguredIpAddress MOV dwErrorCode, EAX ; Move the error code into the error code variable. CMP dwErrorCode, INADDR_NONE ; Compare the result to INADDR_NONE for an error. JE _inetError ; Jump if there was an error parsing the address. MOV dwIPAddress, EAX ; Move the result to the DWORD address variable. ; Move the IP address DWORD into instructions array: MOV EAX, OFFSET arINetAddrInstructions ; Move instructions offset to EAX. MOV ESI, dwIPAddress ; Move DWORD IP address into ESI. MOV DWORD PTR[EAX + 1], ESI ; Move the IP into instructions. ; Launch the targeted game client: INVOKE CreateProcess, ADDR szProcessName, ADDR szCommandLineArguments, NULL, NULL, NULL, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, ADDR structStartupInfo, ADDR structProcInfo MOV dwErrorCode, EAX ; Move the error code into the error code variable. CMP dwErrorCode, 0 ; Compare the result to zero. JE _createProcessError ; Jump if an error occurred. ; Get the targeted module's address space: INVOKE GetModuleHandle, ADDR szModuleName MOV dwModuleAddress, EAX ; Move the returned address to the module address DWORD. CMP dwModuleAddress, NULL ; Compare the address to NULL. JE _getWSAModuleError ; Jump if the address is NULL (error occurred). ; Get the targeted function's address in the module: INVOKE GetProcAddress, dwModuleAddress, ADDR szINetFunctionName MOV dwINetFunctionAddress, EAX ; Move the returned address to the function address DWORD. CMP dwINetFunctionAddress, NULL ; Compare the address to NULL. JE _getINetFunctionError ; Jump if the address is NULL (error occurred). ; Wait for the client to become available for processing: INVOKE WaitForInputIdle, structProcInfo.hProcess, INFINITE MOV dwErrorCode, EAX ; Move the error code into the error code variable. CMP dwErrorCode, 0 ; Compare the result to zero. JNE _waitForInputIdleError ; Jump if the error code is not zero. ; Write the instructions for our inet_addr function to memory: INVOKE WriteProcessMemory, structProcInfo.hProcess, dwINetFunctionAddress, ADDR arINetAddrInstructions, SIZEOF arINetAddrInstructions, NULL MOV dwErrorCode, EAX ; Move the error code into the error code variable. CMP dwErrorCode, 0 ; Compare the result to zero. JE _writeToProcessError ; Jump if the error code is zero. _endProgram: ; End the program and dispose of the Windows Socket API: CMP bdWSAStarted, FALSE ; Check if the WSA has been started. JE _terminate ; If it has not, skip the clean up. INVOKE WSACleanup ; If so, clean up the WSA. _terminate: INVOKE ExitProcess, EXIT_SUCCESS ; Terminate threads & release resources. ; --------------------------------------------------------------------------------------------------------- ; Critical Error Messages ; --------------------------------------------------------------------------------------------------------- _currentDirectoryError: INVOKE MessageBox, NULL, ADDR szErrorCurrentDirectory, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _socketStartupError: CMP dwErrorCode, WSASYSNOTREADY JNE _socketStartupErrorElse1 INVOKE MessageBox, NULL, ADDR szErrorWSANotReady, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _socketStartupErrorElse1: CMP dwErrorCode, WSAVERNOTSUPPORTED JNE _socketStartupErrorElse2 INVOKE MessageBox, NULL, ADDR szErrorWSANotSupported, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _socketStartupErrorElse2: CMP dwErrorCode, WSAEINPROGRESS JNE _socketStartupErrorElse3 INVOKE MessageBox, NULL, ADDR szErrorWSAInProgress, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _socketStartupErrorElse3: CMP dwErrorCode, WSAEPROCLIM JNE _socketStartupErrorElse4 INVOKE MessageBox, NULL, ADDR szErrorWSALimit, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _socketStartupErrorElse4: INVOKE MessageBox, NULL, ADDR szErrorWSAGeneric, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _readConfigError: INVOKE MessageBox, NULL, ADDR szErrorIniRead, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _inetError: INVOKE MessageBox, NULL, ADDR szErrorInet, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _createProcessError: INVOKE GetLastError MOV dwErrorCode, EAX CMP dwErrorCode, ERROR_FILE_NOT_FOUND JNE _createProcessErrorElse1 INVOKE MessageBox, NULL, ADDR szErrorProcessNotFound, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _createProcessErrorElse1: CMP dwErrorCode, ERROR_ACCESS_DENIED JNE _createProcessErrorElse2 INVOKE MessageBox, NULL, ADDR szErrorProcessAuth, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _createProcessErrorElse2: INVOKE MessageBox, NULL, ADDR szErrorCreateProcess, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _getWSAModuleError: INVOKE MessageBox, NULL, ADDR szErrorGetWSAModule, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _getINetFunctionError: INVOKE MessageBox, NULL, ADDR szErrorGetINetFunc, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _waitForInputIdleError: INVOKE MessageBox, NULL, ADDR szErrorProcessWait, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram _writeToProcessError: INVOKE MessageBox, NULL, ADDR szErrorMemoryWrite, ADDR szMessageBoxTitle, MB_ICONERROR JMP _endProgram ; --------------------------------------------------------------------------------------------------------- ; Procedure: Combine Strings ; --------------------------------------------------------------------------------------------------------- ; This procedure combines two strings together, given the source pointer, destination pointer, and length ; of characters to copy. The result is stored in the destination. ; --------------------------------------------------------------------------------------------------------- CombineStrings PROC USES ECX ESI EDI EDX, lSourcePtr:DWORD, lDestinationPtr:DWORD, lLength:DWORD ; Initialize the loop: MOV EDI, lDestinationPtr MOV ESI, lSourcePtr MOV ECX, lLength _loopCopyString: MOV DL, [ESI] MOV BYTE PTR[EDI], DL INC ESI INC EDI LOOP _loopCopyString RET CombineStrings ENDP END start
- Spirited






