Alright, here's the technical detail.
When you start sro_client.exe by hand it says "Run Silkroad.exe". How does sro_client.exe know who the caller is? Most probably because it gets passed some commandline args. So I wrote a little tool that I called sro_client.exe, put it into the Silkroad directory and launched Silkroad.exe to see the arguments.
They looked like
Code:
sro_client.exe [randomnumber] /18 0 0
If you try to launch a second SRO it says "Silkroad is already running!" or something like that. So let's fix it.
I launched IDA and disassembled sro_client.exe which takes quite some time. Because I knew the technique used to make a program unique are mutexes, I searched for CreateMutex references and I think there were two. So basically had to patch the code to ignore ERROR_ALREADY_EXISTS, the error CreateMutex returns if the mutex already exists. Wrote a launcher for, tried it but after some time of loading a messagebox with unreadable text appeared and SRO quitted. Crap.
If I could've read the text I could've searched for the stringref and see what caused it but thanks to the gibberish I had to go through the shitlong list of MessageBox xrefs to see what rougly looked like the one I saw and eventually found it.
Here's the code
Code:
.text:00722017 call DoSocketShit .text:0072201C test eax, eax ; Probably false if bind() failed? .text:0072201E jnz short loc_72208B .text:00722020 push ebx ; uType .text:00722021 push offset aSilkroad ; "Silkroad" .text:00722026 push offset aIXBR_ ; "¢Ã+®À+ÁÕ¦í +¦¦¦ ¢ÃÃÓ -¯ +Ȧ¤¦+." .text:0072202B push ebx ; hWnd .text:0072202C call ds:MessageBoxA
Because I knew eax was zero when the message box appeared I looked for early retn out of the routine and found it.
It checked if a call to bind() failed. Well, when can bind() fail? When the port we're trying to bind to is taken and indeed, the port SRO tries to bind to is hardcoded:
Code:
push 15779 ; hostshort mov [esp+1ACh+name.sa_family], AF_INET call ds:htons push 0 ; hostlong mov word ptr [esp+1ACh+name.sa_data], ax
- Load sro_client.exe with the commandline
- Fix two jumps so a failing CreateMutex doesn't matter
- Make the port random
Rather easy task, here's the code
Code:
#include <windows.h>
#include <stdio.h>
#include <time.h>
//Used to fix two jnz to jmp
void FixJump(HANDLE hProc,void *addr)
{
char Hax[] = {0xEB};
WriteProcessMemory(hProc,addr,Hax,1,NULL);
}
//Fix bind() failing
void RandomPort(HANDLE hProc)
{
srand(time(NULL));
DWORD port = rand()%2000; //purely arbitrary number
port+=15779;
WriteProcessMemory(hProc,(void*)0x9C1794,(void*)&port,4,NULL);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
PROCESS_INFORMATION ProcInf;
STARTUPINFO StartUpInf;
char path[255];
GetCurrentDirectory(sizeof(path),path);
strcat(path,"\sro_client.exe 1337 /18 0 1");
memset(&StartUpInf,0,sizeof(StartUpInf));
//Create process
CreateProcess("sro_client.exe",
path,
NULL,NULL,false,
CREATE_SUSPENDED,
0,NULL,&StartUpInf,&ProcInf);
//Get access rights
DWORD dummy;
if(!VirtualProtectEx(ProcInf.hProcess,(void*)0x711280,1,PAGE_READWRITE,&dummy))
{
DWORD err = GetLastError();
char buffer[255];
sprintf(buffer,"Error: %d",err);
MessageBox(NULL,buffer,"31337",0);
return -1;
}
//Now modify the code
FixJump(ProcInf.hProcess,(void*)0x711280);
FixJump(ProcInf.hProcess,(void*)0x7112EC);
//Fix bind error
RandomPort(ProcInf.hProcess);
ResumeThread(ProcInf.hThread);
return 0;
}

Put it into your Silkroad directory and launch it!
Edit: Unfortunately something's still wrong. It indeed allows to start two SRO clients but you can't connect. Trying to sort it out.






