※. 프리서버 레드문은 상표권이 끝난 게임으로 더 이상의 수정이나 운영이 문제가 되지 않는다고 들었습니다. 해당 내용이 잘못됬을 경우에는 admin@hack.kr로 메일부탁드립니다.
개요.
프리서버의 특징으로 유저수가 적은 반면에 맵이 너무나 넒어서 서로 다른맵에 있는 유저들끼리의 대화가 쉽지 않다.
유저들이 외로워하는 이유로 채팅의 말머리에 "!"를 붙여서 시도할 경우에 웹으로 전송이 되게한다. (이후에 웹으로 전달된 메시지가 게임상으로 재전달시킬 생각이였다.)
내용.
먼저 서버파일을 분석해야한다. 레드문의 경우에는 svMapServer.exe파일이 맵마다 인자를 1, 2, 3, 4 같이 주어서 동작하게 된다. 총 60여개정도 실행되던 것으로 기억한다.
뭐 이것 저것 내용 다빼고 서술해보면, 채팅할 때 "!" 를 앞에 붙이면 소켓을 이용해 웹으로 전달될 수 있는 DLL을 코딩했다.
#include <stdio.h>
#include <winsock2.h>
DWORD SendArmyChat = 0x00463070;//->00463070
DWORD FindArmy = 0x0048849c;//->0048849c
DWORD FormatStringMapServer = 0x0048236a;//->0048236a
DWORD StringFunc = 0x00482370;//->00482370
DWORD FormatString = 0x0040836c;//mapcenter func ->0040836C
DWORD ServerSendMessage = 0x0043e0e0; //->0043e0e0
DWORD RET=0;
DWORD i=0;
DWORD j=0;
DWORD k=0;
DWORD F=0;
char buf[256]="";
char buf2[32]="";
char GAMEID[32]=")";
char ChatString[7] = "%s%c%s";
char ChatString2[3] = "%d";
char SLString[13] = "%d:%d:%d:%d.";
SOCKET hSock;
WSADATA wsadata;
SOCKADDR_IN servAddr;
char link[200]="GET http://redmoon.kr/WolrdChat.aspx?GameID=";
char link2[100]="&Content=";
char link3[100]=" HTTP/1.1\r\n"
"Host: redmoon.kr\r\n\r\n";
char temp[4000];
char temp[4000];
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
// AllocConsole();
freopen( "CON", "w", stdout ) ;
return TRUE;
}
__declspec (dllexport naked) void NewMapServerChat()// global chat functions
{
__asm{
MOV EAX,DWORD PTR [ESP+0x10]//stm
MOVSX ECX,BYTE PTR [EAX]//st
MOV i,ECX;
cmp i,5
je exit
cmp i,6
je exit
MOV EAX,DWORD PTR [ESP]//stm
mov j,EAX;
cmp i,2
jne exit
/*ID strcpy*/
mov EAX,DWORD PTR [ESI+0x37E0]
mov dword ptr buf2,EAX;
mov EAX,DWORD PTR [ESI+0x37E1]
mov dword ptr buf2+1,EAX;
-------------------일부 생략-------------------
/*Chat strcpy*/
mov EAX,DWORD PTR [ESP+0x10]
mov ECX,dword ptr[EAX]
mov dword ptr buf,ECX;
mov ECX,dword ptr[EAX+1]
mov dword ptr buf+1,ECX;
-------------------일부 생략-------------------
cmp buf+1,0x21
jne exit
}
__asm{
pushad
}
strcpy(GAMEID,buf2);
for(k=0;buf[k]!=0;k++){
if(buf[k]==0x20){
buf[k]=0x2b;
}
}
WSAStartup(MAKEWORD(2, 2), &wsadata);
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");
servAddr.sin_port = htons(80);
hSock = socket(PF_INET, SOCK_STREAM, 0);
connect(hSock,(struct sockaddr *)&servAddr,sizeof(servAddr));
strcpy(temp,link);
strcat(temp,GAMEID);
strcat(temp,link2);
strcat(temp,buf+2);
strcat(temp,link3);
send(hSock,temp,sizeof(temp),0);
memset(&temp,0,sizeof(temp));
recv(hSock,temp,sizeof(temp),0);
memset(&temp,0,sizeof(temp));
memset(&buf,0,sizeof(buf));
memset(&buf2,0,sizeof(buf2));
closesocket(hSock);
__asm{
popad
MOV EDX,DWORD PTR[ESP]
MOV RET,EDX
pop EDX
add RET,0x69
jmp RET
} /*길드채팅 에러 수정*/
exit:
__asm
{
cmp dword ptr [esp], 0x0043f49d //->0043f49d
je func1
cmp dword ptr [esp], 0x0043FCFB //->0043FCFB
je func2
cmp dword ptr [esp], 0x0046312f //->0046312f
je func3
cmp dword ptr [esp], 0x0043fd19 //->0043fd19
je func4
func1:
MOV EAX,DWORD PTR [ESP+0x10]//stm
MOVSX ECX,BYTE PTR [EAX]//st
cmp ecx, 8
je gchat
retn
gchat:
mov dword ptr [esp], 0x0043f4fb //->0043f4fb
retn
func2:
cmp byte ptr[ebx], 8
je func2gchat
MOV EAX,DWORD PTR [ESI+0x42C8]
retn
func2gchat:
cmp DWORD PTR [ESI+0x37F8], 10
jae func2next
push eax
push ecx
push edx
LEA EAX,DWORD PTR [ESP+0x30]
push 4
push eax
push 23
mov ecx, esi
MOV DWORD PTR [ESP+0x3C],10
CALL ServerSendMessage
pop edx
pop ecx
pop eax
jmp func2exit1
func2next:
mov dword ptr [esp], 0x0043fcff//->0043fcff
retn
func2exit1:
mov dword ptr [esp], 0x0043fd27//->0043fd27
retn
func3:
MOV EAX,DWORD PTR [ESP+0x18]//stm
NOT ECX//st
mov edx,dword ptr[esp+0x14]
cmp byte ptr[edx], 8
je func3gchat
retn
func3gchat:
mov byte ptr [ebx], 8
retn
func4: //여기까지
cmp byte ptr [ebx], 9
jne func4exit2
add esp,8
push edi
xor edi,edi
nextarmy:
sub esp, 4
lea ecx, dword ptr [esp]
Call StringFunc
mov eax, dword ptr [esi+0x42c8]
push eax
lea eax, dword ptr ChatString2
push eax
lea eax, dword ptr [esp+0x8]
push eax
call FormatStringMapServer
mov ecx, dword ptr [esi+0x4504]
add ecx, 0x3310
mov eax, dword ptr [esp]
mov eax, dword ptr [eax]
mov dword ptr [esp],eax
mov eax, dword ptr [FindArmy]
mov eax, dword ptr [eax]
call eax
add esp, 0xC
add eax, 0x14
inc edi
lea eax, dword ptr [eax+4*edi]
cmp edi, 5
ja func4exit1
mov eax, dword ptr [eax]
cmp eax, 0
je nextarmy
mov ecx, dword ptr [esi+0x4504]
mov edx, dword ptr [esp+0x28]
push edx
push eax
call SendArmyChat
jmp nextarmy
func4exit1:
pop edi
push 0x0043fd27//->0043fd27
retn
func4exit2:
add esp, 4
push eax
call SendArmyChat
push 0x0043fd27//->0043fd27
retn
}
}
__declspec (dllexport naked) void NewMapCenterChat()
{
__asm
{
cmp dword ptr [esp], 0x00404D77//->
je func1
cmp dword ptr [esp], 0x00404F8E//->
je func2
cmp dword ptr [esp], 0x00407133//->00407133
je func3
cmp dword ptr [esp], 0x00405243//->
je func4
}
__asm
{
func1:
cmp esi, 8
je gchat
cmp esi, 9
je achat
ADD ESI,-3//st
CMP ESI,3//st
retn
gchat:
mov dword ptr [esp], 0x00404D8D//->
retn
achat:
mov dword ptr [esp], 0x00404DA7//->
retn
func2:
mov eax, dword ptr [esp+0x8]
cmp eax, 8
je func2gchat
MOV EAX,DWORD PTR [ESI+0x21C4]//st
retn
func2gchat:
mov dword ptr [esp], 0x00404FA4
retn
func3:
mov eax, dword ptr [esp+0x44]
cmp eax, 8
je func3gchat
pop eax
push 0x0040DA28//st ??
push ecx//st
push eax
retn
func3gchat:
mov eax, dword ptr [esp+8]
findnameend:
cmp byte ptr [eax], 0x0A
je next
inc eax
jmp findnameend
next:
mov byte ptr [eax],0
add eax, 1
mov dword ptr [esp+8], eax
sub eax, 2
findnamestart:
cmp byte ptr [eax], 0x0
je next2
dec eax
jmp findnamestart
next2:
add eax, 1
add esp,8
push 12
push eax
lea eax, dword ptr ChatString
push eax
push ecx
call FormatString
add esp,4
push 0x00407138//->00407138
retn
func4:
cmp dword ptr [esp+8], 9
jne func4exit2
mov ecx, eax
push esi
mov esi, dword ptr [eax-8]
func4findsymbol:
cmp byte ptr [ecx], 0x0A
je func4achat
inc ecx
dec esi
je func4exit1
jmp func4findsymbol
func4achat:
mov byte ptr [ecx], 0x0D
func4exit1:
pop esi
MOV ECX,DWORD PTR [EDI+0x21C0]//st
retn
func4exit2:
MOV ECX,DWORD PTR [EDI+0x21C0]//st
retn
}
}
하지만 원하는 기능이 개발된 DLL을 서버파일에서 사용하지 않는다면 의미가 없다. 서버파일을 실행시마다 매번 DLL인젝션으로 넣어줄 수도 없지 않은가?
PE헤더에 내가만든 "rmKMS.dll의 NewMapServerChat, NewMapCenterChat 함수를 참조시킨다면 자연스레 실행시마다 rmKMS.dll 파일을 사용 할터였다.
위 사진의 지정한 "00"*16 공간은 건드릴 수 없다. 뒤에 여유공간이 없는 터이다.. "00"르로 차있는 부분이 한 블럭만치만 더있었다면..
그러나 파일의 어딘가에 빈 메모리공간은 충분히 존재한다. 나는 리소스 영역의 뒷편으로 "IMPORT Directory Table" 섹션을 빈 노란 공간으로 복사시켰다. 그리고 보라색 영역에 우리가 추가할 함수에 대해 추가해주었으며, 복사한 영역을 참조해 실행하도록 수정했다.
함수의 이름에서 2바이트 공간을 비워놨던 이유는 .. 아래 사진을 참고하자. 그렇게 필수적이진 않다고 한다 ㅇㅇ;
이제 서버에서 채팅을 받았을 때 함수가 호출되게 하면 모든 것이 완벽해졌다.
어셈블리어로 스택을 직접 참조해서 동작하기 때문에 Hexray로는 이해되지 않는다. 하지만 사용자가 별개로 만든 DLL을 참조하고 더 이상의 개발이 불가능한 게임에 새로운 기능이 도입되었다는데 의의가 있다.
동작하는 부분에 대해서는 아래를 확인하면 될 것 같다.
[동작 영상]
'리버싱' 카테고리의 다른 글
[모바일악성코드] 어딘가 이상한 택배 문자를 받았다. (0) | 2020.09.04 |
---|---|
안드로이드 dex, Native 를 동시 디버깅 하는 방법 (1) | 2020.05.04 |
[HackShield] SDK Version 5.7.14.555 Bypass (10) | 2019.12.02 |
안드로이드 리퍼블릭 분석 (1) | 2019.09.19 |
카카오 멜론 DRM 해제하기 ( .dcf -> .mp3 ) (40) | 2019.06.22 |
댓글