ld.exe는 ldplayer에서 내부적으로 실행중인 LDPlayer의 VitrualBox console에 접속하기 위해 사용된다.
Default usage:
.\ld.exe -s <index>
session 값을 주지 않을 경우 모든 실행중인 에뮬레이터 중 하나에 연결된다.
ld.exe는 어떻게 창에 attach할까.
IDA로 분석해봤다.
CPP로 작성되었고, start 함수에서 CRTStartup 함수로 이동한다.
CRTStartup -> wmain
wmain 함수는 두개의 int pointer를 인자로 받는데, 이 값은 pre_cpp_init에서 초기화된다.
dword_406414에 *argc,
dword_406418에 ***argv 가 담긴다.
__tmainCRTStartup에서는 wmain에 env까지 인자로 넘겨주지만, 실제로 받는 값은 argc, argv만 받는다.
wmain 함수에는 사실상 모든 로직이 다 담겨있었다.
-s 옵션을 주면 특정 ldplayer session에 연결할 수 있게끔 처리가 되어있다.
session id값은 v30에 들어간다.
추가 인자도 처리를 하는거로 보이지만, 쓰이는 곳은 찾을수 없었다.
console handle을 가져오는 부분을 살펴보자.
FindWindowExW를 사용해서 핸들을 가져오는 모습을 볼 수 있다.
window classname: leidian4_process_msg_wnd_class
lpszWindow: Buffer
wchar_t Buffer[128];
Buffer에는 snwprintf_s 함수를 활용해 "leidian4_process_msg_wnd_%u" 포맷으로 write한다.
%u에는 v30 | (v9 << 24) 가 들어가는데,
v30 = session id
xmmword_404210 = 380036003000300030003000390030h
v9 = xmmword_404210을 long long integer로 변환한 값 OR 0 이 된다.
테스트
ID가 300인 에뮬레이터의 콘솔을 가져와보겠다.
#include <immintrin.h>
#include <Windows.h>
#include <iostream>
#include <format>
int main()
{
unsigned int sign = 0x050000;
unsigned int session = 300;
wchar_t windowName[0x80];
memset(windowName, 0, sizeof(windowName));
_snwprintf_s(windowName, 0x80u, 0xFFFFFFFF, L"leidian4_process_msg_wnd_%u", session | (sign << 8));
HWND hwnd = FindWindowExW(NULL, NULL, L"leidian4_process_msg_wnd_class", windowName);
if (hwnd == NULL)
{
std::cout << "Not found" << std::endl;
}
else
{
std::cout << "Found" << std::endl;
std::cout << "HWND: " << hwnd << std::endl;
}
std::cout << "windowName: " << windowName << std::endl;
return 0;
}
HWND를 잘 받아오는 모습을 볼 수 있다.
명령어를 보내는 코드는 아래와 같다.
SendMessageW(hwnd, 0x4Au, (WPARAM)hwnd, (LPARAM)(L"poweroff"));
데이터 수신은 아직 구현하지 않았다.
'리버싱' 카테고리의 다른 글
아오오니 레전드 (2014) 분석 #1 (0) | 2024.06.22 |
---|---|
Firefox cookie, local storage 추출 (0) | 2024.04.26 |
[Zeta] 대화하기 (0) | 2024.04.22 |
[Zeta] OAuth token 추출 (0) | 2024.04.22 |
Zeta (구 Nutty) (0) | 2024.04.21 |