9번 문제 : 송영균 이병의 제대일을 구하세요.
문제풀이------------------------------------------------------------------------------------------------
9번 문제 :
1. 출제의도 :
이문제를 낸 이유는
리버싱을 할때 분석만이 다가 아니라
적절한 프로그램을 코딩해서 풀수도 있다는(Brute Foces 이용)것을 보여주기 위해 출제했습니다.
이문제는 심플스(Simples) 18번 문제를 표절해서 만들었습니다...... ㅎ
2. 문제풀이 :
프로그램을 실행시키면
와 같이 콘솔창 하나와 메시지 박스 하나가 떠있습니다.
메시지 박스의 확인 버튼을 누르게 되면 날짜가 하나씩 증가합니다.
이문제는
1. 리버싱 수행단계를 거칠필요 없이 바로 Brute Force 툴을 만들거나 (자동으로 확인 버튼을 클릭하는)
2. 디버거로 날짜를 비교하는 구문을 찾아내면 될것 같습니다.
1번방법 :
FindWindow 함수로 메시지 박스의 핸들값을 얻어낸후
FindWindowEx 함수로 버튼의 핸들값과 텍스트의 핸들값("0일 후인가???" 부분)을 알아냅니다.
그후 SendMessage 를 이용하여 텍스트의 내용을 WM_GETTEXT 로 얻어오고
BM_CLICK 을 이용해 버튼을 클릭합니다.
소스입니다.
(중간중간에 sleep 를 써준건 메시지 박스가 뜨는 시간이나 메시지를 보내는 시간을 고려하여
안정되게 프로그램을 돌리기 위하여 동기화(저질수준...)를 해준겁니다)
위 소스를 컴파일 하여 프로그램을 돌리면 답이 나오는걸 알 수가 있습니다.
(저희 동아리 애들 대부분은
이문제를 마우스 커서를 움직여 버튼을 클릭하는 그런 게임용 매크로를 써서 풀더군요. ㅠㅠㅠ)
2번방법 :
디버깅하여 날짜를 비교하느 구문을 찾아 답을 구하는 방법입니다.
올리디버거를 실행시킵니다.(OllyDbg)
메시지 박스가 생성되므로 Back to User 를 이용해보겠습니다.
(유저가 실행한 영역까지 코드를 진행시키는 기법입니다)
Run을 하신 후 Pause 를 걸고 Alt + F9를 눌러 Back to user 를 겁니다.(후측 하단에 Back to user 표시)
어랏?? 근데 메시지 박스가 클릭이 안됩니다.
여기서 멀티쓰레드로 구현됬다는걸 알수가 있습니다.
(올리디버거는 하나의 쓰레드 밖에 트레이싱 할수 없습니다.
지금 우리가 보고 있는 쓰레드는 메시지 박스를 생성하는 쓰레드가 아니라는것을 알수 있습니다.)
이럴땐 Executable Module 기법을 사용합니다.
(실행 가능한 모듈을 골라서 중요한 코드에 BreakPoint 를 걸어놓음으로써
해당 코드가 실행될 때에 제어권을 올리디버거로 받아 문제를 해결할 수 있는 기법입니다)
Restart (Ctrl + F2)를 하신 후 메뉴 아이콘에 E를 눌러줍니다.
위의
dakuo@2.exe 모듈을 클릭합니다.
2개의 MessageBoxW 함수 호출문이 나오는데
1번째는 잘모르겠고 2번째는 성공한 메시지 인거 같습니다.
여기서는 첫번째 메시지 박스가 더 중요해보입니다.
그 이유는 성공메시지로 흐름을 점프 하는건 아무런 의미가 없습니다.
(WaitForSingObject 로 메시지 박스 호출을 완전히 마친 쓰레드가 종료될까지 기다린 후
최종 날짜값을 받아서 출력해주기 때문)
따라서 제대일을 매번 출력해주는것으로 보이는 첫번째 메시지 박스 호출문에 BP (BreakPoint)를 걸고
실행해보겠습니다.
0040101B . 8B3D 2CA14000 MOV EDI,DWORD PTR DS:[<&USER32.MessageBo>; USER32.MessageBoxW
: MessageBoxW 의 함수 주소를 EDI 에 옮깁니다.
PUSH ECX
PUSH 0
CALL EDI
: 파라미터를 PUSH 한 후 EDI 즉, MessageBoxW 함수를 CALL 합니다.
CMP EAX, 1838
MOV DWORD PTR DS:[40D9E8], EAX
JNZ SHORT dakuo@2.00401021
: EAX와 1838값을 비교한후 JNZ 즉, 0이 아니면 위로 돌아갑니다. 이후 이 루틴이 반복됩니다.
감이 오시나요????
EAX값이 1838이 안되면 계속 메시지가 반복되서 출력됩니다.
1838은 Hex값입니다. Dec으로 바꾸면 답이되겠네요 ㅎ
3. 문제소스
소스를 보시면 디버깅을 약간 어렵게 하기 위해 멀티 쓰레드로 구현했습니다.
쓰레드 수를 더 늘리고 암호화를 해서 꼬아 놓을까 하다가 그냥 참았습니다.ㅋ
프로그램의 흐름은
1. 쓰레드를 하나 만든다.
2. 만든 쓰레드에서 메시지 박스를 호출한다.
3. 메인 쓰레드는 만들어진 쓰레드가 종료되길 기다리다가 쓰레드가 종료되고 나면
날짜값을 성공메시지에 담아서 출력한다.