6월, 2019의 게시물 표시

리버싱kr easy_unpackme 풀이

이미지
리버싱kr의 세 번째 문제인 easy_Unpackme를 풀어보려 한다. 제공된 텍스트 파일에 적힌 것을 보면 OEP(Original Entry Point)를 찾으라고 한다. exeinfope로 본 엔트리 포인트는 이상한 곳을 가리키고 있다. 실행 파일의 엔트리 포인트가 이상한 곳으로 잡혀 있고, 원래의 엔트리 포인트를 찾아 그 주소로 auth 인증을 하는 것 같다. 참고로 올리 2버전에선 올리가 알아서 oep를 찾아서 처음에 위치시키기 때문에 문제를 푸는 의미가 없어진다. 그렇기 때문에 풀이에는 x64dbg를 이용했다. 파일을 불러왔다. 모듈 ntdll.dll에서 시작하고, 전혀 모르겠는 주소로부터 시작한다. 보통 실행 파일은 내가 만든 사용자 코드로부터 바로 시작하지 않기 때문에 ntdll으로부터 실행 파일의 매개 변수 등을 받는 여러 실행코드를 거쳐 사용자 코드까지 이르게 된다. ntdll의 모든 함수들을 하나하나 따라갈 필요 없이 좀 내려가면서 크게크게 보고 넘기는 편이 빠르게 찾을 수 있을 것이다. f8로 트레이싱 해 가며 대충대충 따라가 보자. 크게크게 넘기다 보니 모듈이 unpackme.exe로 바뀐 것을 볼 수 있다. 함수를 안으로 단계 진행을 통해 따라갈 필요는 없지만 함수명 등은 잘 봐두면서 넘어가면 좋다. LoadLibraryA, GetProcAddress, GetModuleHandleA라던가 함수명을 보면 대충 실행코드 전인지 때려맞추게 된다. 리버싱 책이나 강의 등에서도 처음에는 트레이싱 해 가며 이런 함수들이 나오는 것을 자주 봐 두면 눈에 익어 도움이 된다고 한다. 좀 더 내리다 보니 많은 점프문과 VirtualProtect함수를 호출하는 것이 보인다. 그 아래에는 GetProcAddress함수가 보인다. 아직 전체적인 흐름으로 봐선 프로그램의 oep는 나오지 않은 것으로 보인다. f8을 통해 빠르게 진행시켜 넘겨보자. 쭉 내리다 보니 코드가 없는 빈 공간이 시

리버싱kr easy_Keygen 풀이 2

이미지
이전까지 이름을 넣었을 때 이름을 넣은 것을 어떤 루틴을 통해 시리얼 값으로 변해 메모리에 저장되고, 그 값과 시리얼을 정확히 맞추면 풀린다는 것을 깨달았다. 게싱과 실험이 난무한 풀이였지만 일단 작성해 보도록 하겠다. 이름에 1234를 넣었을 때의 시리얼 값은 21120324였다. 어떠한 규칙이 있을 지 일단 이름을 1111을 넣고 다시 실행시켜 보자. 시리얼까지 입력받고 난 뒤의 실행문이다. 시리얼이 저장되는 위치는 따로 바뀌지 않았으며, esp + 74의 위치를 덤프창을 통해 본 결과 0019FE7C  32 31 31 31 30 31 32 31 00 00 00 00 00 00 00 00  21110121........ 시리얼  값은 "21110121"인 것을 볼 수 있다. 아직 어떠한 규칙인지 잘 모르겠을 수 있다. 1111을 넣고 다시 실행하여 시리얼을 입력받기 전, 반복문을 한 번 돌려보았다. 시리얼 값이 들어가는 주소에 32 31, 즉 "21"이 들어가 있는 모습을 볼 수 있다. 단순 추측으로 한 문자당 두 문자로 바뀐다면, 시리얼의 길이는 문자열의 길이 * 2일 것이다. 루틴 부분을 좀 크게 봐보자. ecx와 edx를 사용해 시리얼을 만드는 연산을 하는 것 같고, 반복문에서 문자열의 위치 인덱스를 증가시키는 것을 esi와 esp를 사용하는 것으로 보인다. 그리고 xor연산을 통해 ecx, edx를 xor을 하고 ecx의 값을 스택에 넣은 뒤 어떤 함수를 호출한다. ecx가 가진 카운터와 ebp를 비교해 jl인 동안 반복문을 실행한다. 레지스터 창을 보면 ebp의 값은 1인 것을 볼 수 있다. ebp의 원래 값을 백업해 두고 카운터로 사용하는 것을 볼 수 있다. 추측으로, '1'을 반복문을 한 번 거치고 나서 '21'이 되었다고 하자. 1을 어떻게 연산해서 연산 결과를 그대로 두 바이트로 쪼개

리버싱kr easy_Keygen 풀이 1

이미지
reversing.kr 두 번째 문제로 이지키젠을 풀어보았다. 이전에 이지크랙미보다 훨씬 분석을 덜 하고 게싱으로 푼 게 조금 아쉽다면 아쉽다. 실행 시 이름과 시리얼을 받아 맞음이나 틀림을 띄워준다. 그리고 reversing.kr 풀이에 필요한 auth 키는  제공된 텍스트 파일의 예시 시리얼일 때의 이름을 찾는게 auth 키를 찾는 것이다. x64dbg로 열어보자. easy keygen모듈을 들어가니 바로 눈에 띄게 사용자 코드가 보인다. 일단 이름을 1234를 넣고 bp를 걸어서 잠깐 보기로 했다. 함수를 호출하고 난 뒤 스택창의 "1234"가 들어가있는 주소를 덤프창에서 확인해 보니 잘 들어가있다. 문자열들은 esp + 18의 주소의 위치에 상주해 있는 것을 다음 실행문 확인 테이블?에서 볼 수 있다. 다음으로, 아래를 내려가 보니 반복을 통해 문자열을 패치 시킬 것 같은 위치를 발견했다. bp - f9를 통해 반복문을 빠져나왔다. 그 후에 시리얼을 입력받는 부분을 5678을 입력해 보았다. 호출부를 빠져나와서 아래를 보니 문자열을 dl, cl을 통해 비교하려는 실행문이 보인다. esp + 74번지에 시리얼로 추측되는 문자열이 들어가 있고, 현재 실행문에 걸쳐진 esi가 그 주소를 가지고 있는 것을 볼 수 있다. 덤프창에서도 이전엔 아무것도 없었던 위치에 esi가 가리키는 문자열이 잘 들어있는 것을 확인할 수 있다. 저 주소에 담긴 문자열이 시리얼인지 실행창을 하나 띄워 단순히 값을 복사해 때려박아 보았다. 너무 쉽게 풀려버렸다. 그런데 문제에서 요구하는 auth 키를 찾으려면 반대로 생각해야 하기 때문에 현재는 알 수 없다. 시리얼이 이름을 가지고 일정 값으로 변하는 거라면, 그 루틴을 풀 방법을 찾아보아야 한다.

리버싱kr easy_crackme풀이 3

이미지
이전에 두 번째 루틴까지 풀었다. 풀은 루틴까지 적용시켜 빠르게 디버깅 해 보기 위해 이전 루틴들을 맞춘 상태로 실행시켰다. 이전 루틴 다음줄까지 다른 수정 없이 바로 진행되는 것을 볼 수 있다. 다시 시작해보자. 따로 함수 호출을 하진 않지만 많은 연산을 거치며 마지막에 test연산을 통해 루틴 검사를 하는 것을 볼 수 있다. esi와 ebx의 레지스터를 온전히 사용하기 위해 스택에 push해 백업하고, esi에 "R3versing"이라는 문자열을 복사한다. push를 2번 하여 스택 포인터, 즉 esp가 가리키는 위치는 두 번 증가하였고, esp + 10의 위치는 입력한 문자열의 5번째 위치, 숫자 '1'의 위치이다. 문자열이 있는 주소를 eax에 복사하여 넣어준다. 그 후 dl과 bl에 각각 eax와 esi가 가진 데이터를 바이트 크기로 복사하여 값을 넣은 것을 볼 수 있다. 두 실행문을 실행하고 난 결과이다. ebx에는 "R3versing" 문자열의 바이트 크기 첫 번째 문자 'R'이 들어갔고, edx에는 "12345667" 문자열의 바이트 크기 첫 번째 문자 '1'이 들어갔다. 그 후에 cl에 dl의 값을 복사한 뒤, cmp로 dl과 bl을 비교하여 같지 않으면 점프하는게 보인다. 내용이 비슷한게 있어보이니 하나하나 보기보단 조금 큰 흐름으로 봐보자. 세 번째 루틴이다. 마지막에 test eax, eax를 통해 틀렸는지 검사해 Incorrect로 점프하는 곳이 있다. 그 위를 보면 xor eax, eax를 톻해 eax레지스터의 값을 0으로 만들고 test실행문에 점프하는 곳이 있다. 앞전에도 알아낸 결과로 생각하면 xor을 통해 레지스터의 값을 0으로 만들고 test실행문을 거치면 equal이 나온다. 그럼 004010FE 식을 실행하면 된다. sbb연산을 통해 eax의 값을 0이

리버싱kr easy_crackme풀이 2

이미지
편의상 ButtonListner라는 레이블을 붙여보자. 주요 내용을 훑어보자. 함수 프롤로그는 대충 보고 GetDigItemTextA라는 함수를 호출하는 것이 보인다. 텍스트박스의 텍스트를 가져오는 함수인 것 같다. https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getdlgitemtexta#parameters 대화 상자의 핸들러, 컨트롤러의 아이디?, 문자열을 입력받을 버퍼 위치, 버퍼의 크기 순 인자인것 같다. 스택에 들어가는 순으로 보면 eax가 가장 마지막 인자이고, 인자가 총 3개 들어가는 것을 보니 getDigItemTextA의 상위 함수 중 문자열 길이를 받지 않는 3개의 인자를 받는 함수를 사용한 듯 싶고, eax에 들어가는 주소가 문자열을 받아 저장하는 버퍼의 주소인 듯 싶다. 함수를 호출 후 eax에 들어있는 주소를 덤프 창에서 한번 확인 해 보자. 0019F6F4엔 아무것도 없다. 함수를 호출하고 나면, 메모리에 입력했던 123이 들어간 것을 볼 수 있고, 함수의 리턴값을 받아온 eax가 3의 값을 가지는 것을 볼 수 있다. 3은 문자열 길이로 추정된다. 여길 다시 보면, 함수를 호출하고 나와서 스택을 정리하지 않고 바로 실행문이 나오고, 이미 정리된 스택의 위치를 가리키는 esp스택의 4바이트 뒤에 다시 저장된 문자열의 주소가 나온다. 함수를 호출하고 난 뒤의 바로 다음 실행문은 비교를 위한 cmp문이다. esp + 5는 문자는 4바이트 뒤부터 시작하는 문자열의 2번째 문자로서 123에서 2를 가리키고 있다. '2'와 'a'를 비교하고 있다. jne 401135인데, 같지 않으면 점프한다. 점프된 곳을 따라가보자. Incorrect Password를 인자로 넣은 메시지 박스를 띄우고 리턴한다. 이 주소가 password를 검사하는 루틴에서 틀렸을 때 점