활용강의: 리버싱 이 정도는 알아야지 - 섹션 3
1. 예제분석 #01 - 도전과제
- Sample 02.exe 실행시켰을 때 command 창이 뜨지만 아무 동작 없이 실행이 종료된다.
!!도전 과제!!
=> Sample 02.exe가 “ If Code!! “ 문자열을 출력하도록 만들기.
=> 전체적인 동작을 이해하고, 문자 해결을 위해 어디를 어떻게 고쳤는지 파악하기.
=> 힌트 : “if 조건문"을 사용해서 만들었습니다.
2. 예제분석 #01 - 코드분석_Level.1 | 흐름 파악하기
▶Sample 02.exe 예상 동작흐름
- Sample 02.exe가 “if 조건문”을 사용해서 만들어졌으므로 ‘if 문’에 들어가는 조건이 일치하느냐에 따라 문자열 출력 여부가 결정될 것 같다.
▶문제 접근 방향
1. 조건 확인 지점을 찾는다.
2. 조건이 맞지 않는 원인을 파악한다.
3. 문제를 해결하고, 확인한다.
3. 예제분석 #01 - 코드분석_Level.2 | 원인 도출
▲ Sampe02.exe 파일을 디버거에 올리고 메인 함수로 이동한다. 한 줄 씩 실행하다 보면 00401048 주소에서 점프를 뛰고 3초 뒤에 메인 함수가 종료되는 것을 확인할 수 있다.
→ 00401048 ~ 00401076 사이에 문자 출력 코드가 있을 것으로 예상할 수 있다.
▲ 점프는 제로플래그를 확인한 후 점프를 뛴다. 여기서는 먼저 제로플래그가 0이기 때문에 점프를 뛴다. 따라서 Z(제로플래그) 값을 1로 수정해준다.
▲ 그리고 다시 코드를 한 줄 씩 실행하다 보면 플래그 값이 0으로 바뀌는 순간이 있다. 그때 그 코드를 확인한다.
→ 00401040의 CMP 비교 코드에서 플래그 값이 변경된 것을 확인
▲ 00401040에 있는 명령어를 읽어본다.
CMP WORD PTR SS:[ESP+4], 7D5 |
→ ESP+4에 있는 두 바이트 값과 7D5를 비교하는 코드
▲ CMP 비교 코드는 값이 같을 때 Z(제로 플래그)에 1을 넣는다. 현재 제로플래그가 0이니까 두 값이 다른 것을 알아챌 수 있다.
→ 값을 같게 만들어서 문제를 해결
▲ ESP+4에서 HEX를 D5 07로 바꾼다.
▲ 그러나 밑에 0040104A와 00401052에도 비교 코드가 있는 것을 확인할 수 있다. 이것도 직접 데이터를 수정한다.
→ ESP+2에서 HEX를 00 00으로 변경, ESP+6에서 HEX를 20 00으로 변경한다.
▲그러면 점프하지 않고 밑의 코드들로 잘 진행됨.
▲ 00401064이 문자열 호출 코드로 예상된다.
→ 실행 결과 문자열 ‘If Code!!’가 출력됨을 확인 가능
*Push 명령어 : 인자를 스택에 쌓는다 (32비트 CPU 기준)
4. 예제분석 #01 – 코드분석_Level.3 | 문제 해결
- 문제가 왜 발생하고 어떻게 해결해야 하는지 고민해본다.
▲ Sample02.exe 파일은 총 3군데에서 값을 비교 진행한 것을 앞에서 확인할 수 있었다.
→ 비교 값이 일치하지 않았기 때문에 문자열이 출력되지 않음
▲ 첫 번째 비교 코드가 있는 주소로 이동해 00401040 주소의 ESP+4가 무엇을 가리키는지 확인한다.
→ 0012FE38
▲ 두 번째 비교 코드가 있는 주소로 이동해 0040104A 주소의 ESP+2가 무엇을 가리키는지 확인한다.
→ 0012FE3A
▲ 세 번째 비교 코드가 있는 주소로 이동해 00401052 주소의 ESP+6이 무엇을 가리키는지 확인한다.
→ 0012FE3E
▲ 0040103A 지점에서 ‘GetLocalTime’을 호출한다. 여기에 0012FE38이 인자값으로 들어간다. 그리고 실행하면 값이 들어온다.
GetLocalTime Function - API 정의 Retrieves the current local date and time To retrieve the current date and time in Coordinated Universal Time (UTC) format, use the GetSystemTime function. |
▲ GetLocalTime()은 현재의 날짜와 시간 정보를 얻을 수 있는 API이다. 인자로 들어온 LPSYSTEMTIME에 시간 정보가 들어온다. SYSTEMTIME은 연, 월, 요일같이 다양한 시간 정보를 담을 수 있게 구성되어 있다. 이 API를 호출하고 나면 구조체에 시간 정보가 들어가는 것이다.
▲ 다시 코드를 살펴보자. 0X7D5 = 2005다. 지금 현재 2023년이기 때문에 아무리 Local time을 호출해도 2005가 들어올 수는 없다. 그래서 일치하지 않았던 것이다.
▲ 다시 돌아가서 확인하면 7D5, 0, 20 순서대로 연, 월, 일 정보이다.
문제 해결 방안 - GetLocalTime() 함수 호출 결과, 입력되는 시간 정보를 수정한다. - 대조군에 해당하는 값인 0x07D5, 0x00, 0x20을 적절히 수정한다. - CMP 명령어 실행 결과, 0으로 설정되는 ZF 레지스터 값을 1로 수정한다. - 비교 결과에 대한 실행 코드인 ‘JNZ 조건 점프’를 반대로 동작하게 만든다. |
5. 예제분석 #02 - 도전과제
- sample03.exe 파일을 실행했을 때 실행 화면은 뜨지만 어떤 동작인지는 모른다.
- Hex 값을 확인하면 For Code! 문자열이 포함되어 있는 것을 확인할 수 있다.
- 따라서 문자를 출력하는 방식에 문제가 있을 것으로 추정하고 문제에 접근한다. (아마 메모리에 문자가 있을 것 같다.)
!!도전과제!!
=> Sample 03.exe가 “For Code!!” 문자열을 출력하도록 만들어보세요.
=> 전체적인 동작을 이해하고, 문제 해결을 위해서 어디를 어떻게 고쳤는지 파악해야 합니다.
=> 힌트: ‘for 반복문’을 사용해서 문자가 하나씩 출력되도록 만들었습니다.
6. 예제분석 #02 - 코드분석_Level.1 | 흐름 파악하기
[“A” 문자 출력 과정]
1. 0x200주소에서 1바이트 값을 가져온다.
2. 이 값을 출력한다.
※ 두 가지 출력 방식을 생각할 수 있다.
1) 0x200에서 값을 가져온 다음, 변형해서 출력한다. (0x41(A의 아스키 값) + 0x6 =0x47(G의 아스키 값)
2) 0x200이 아니라 엉뚱한 주소에서 값을 가져와 출력한다. (0x47 => G 출력)
▶Sample 03.exe 예상 동작 흐름
- Sample 03 파일도 아래의 두 가지 출력 방식의 문제 중 한 가지를 가지고 있을 것이다.
1) “For Code!” 문자열의 특정 값과 연산해서 다른 문자열로 만든 후에 출력한다.
2) Sample 03.exe의 .data 섹션에는 “For Code!” 문자열이 기록되어 있다. 그리고 그 외에도 다양한 데이터가 기록되어 있을 것이다. 문자 출력 주소가 바뀌었다면, “For Code!” 문자열이 아닌 다른 데이터가 출력될 수 있다.
7. 예제분석 #02 - 코드분석_Level.2 | 원인 도출
1. main() 함수 찾기
- [F8]로 코드를 한 줄씩 실행하면 main() 함수를 호출하는 주소를 찾을 수 있다.
- main() 함수의 주소 : 00401140
2. 반복되는 구간 찾기
- main() 함수 내부에서 [F8]로 코드를 한 줄씩 실행하면 코드가 반복되는 부분을 찾을 수 있다.
- 00401031 주소부터 00401048 주소 까지 코드가 반복된다.
- command창을 확인하면 문자가 출력되고 있는 것을 확인할 수 있다.
3. 문자 출력 방식 예상하기
- 2번에서 발견한 반복문 구간을 통해 문자 출력 방식을 추측해볼 수 있다.
- 즉, 해당 반복문을 통해 printf(“%s”, “a”)로 문자열이 출력되는 것을 예상할 수 있다.
- 문자 출력을 확인하기 위해 00401036 주소에 [F2]를 눌러 breakpoint를 설정한다.
- 00401036 주소의 ECX 레지스터에 대문자 “S”의 아스키코드 값을 넣는다.
- [F9]를 눌러 sample 03.exe를 실행하면 CMD에 대문자 “S”가 출력되는 것을 확인할 수 있다.
4. ECX 레지스터에 저장되는 값의 위치 찾기
- 00401031 주소의 코드(MOVSX ECX,BYPE PTR SS:[ESP+ESI+4])를 확인한다.
5. “For Code!!” 문자열이 있는 위치 찾기
6. 00401031 주소에 [F2]를 눌러 breakpoint를 설정한다.
7. [SPACE]를 눌러 코드를 수정한다.
- 이때, ESP 레지스터는 스택 포인터를 저장하고 있으므로 EDI 레지스터를 이용한다.
- 즉, MOVSX ECX,BYPE PTR SS:[ESP+ESI+4]를 MOVSX ECX,BYPE PTR SS:[EDI+ESI]로 코드를 수정한다.
8. 다음, [EDI + ESI]가 0x407034 주소를 가리키게 한다. 그러나, ESI 레지스터에는 값 “A” 가 들어가 있으므로, 0x407034에서 0xA를 뺀 값인 0x40702A의 값을 넣는다.
9. 그 후 실행하면 FOR CODE가 실행되는 것을 확인할 수 있다.
8. 예제분석 #02 - 코드분석_Level.3 | 문제 해결
1. 반복 코드를 분석한다.
- ESP+ESI+4 주소에서 1byte 값을 가져온다.
- 가져온 문자를 출력한다.
- ESI 값을 1 증가시킨다.
- ESI 값을 확인한다. 이때, 0X14보다 작으면 문자 출력 코드를 반복 실행시킨다.
2. [ESP+ESI+4] 주소에 있는 값을 확인한다.
- 문자열 “For Code!!”는 0x407034에 위치해있다.
- 그러나 ESI 레지스터에는 값 “A”가 들어있으므로, [ESP+ESI+4]의 주소를 0x40702A로 설정해야 한다.
- 즉, [ESP+ESI+4]의 주소가 0x40702A가 아니어서 이상한 문자열이 출력된 것이다.
3. ESI 레지스터의 값을 0으로 바꾸기
- ESI 레지스터에 값 “A”가 들어가 있는 것을 0으로 바꾼다. (ESP값은 스택 포인터기 때문에 건들지 않는다.)
- 변경된 코드의 모습
4. 값 “A”의 위치 찾기
- 0040102C 주소에서 값 “A”가 ESI 레지스터에 저장되는 것을 확인할 수 있다.
- [F2]를 눌러 Sample 03.exe를 다시 실행한 후 ESI 레지스터에 저장하는 값을 0으로 바꾼다. (NOP으로도 수정 가능)
5. 그 뒤 실행하면 “For Code!!” 문자열이 출력되지만, 쓰레기 값도 같이 출력되는 것을 확인할 수 있다.
- 총 20개의 문자열이 출력되는 것을 확인할 수 있다. (10개만 출력되어야 하는데 20개가 출력되었다.)
6. 쓰레기 값이 같이 출력되는 이유
- 반복 코드에서 00401045 주소의 코드(CMP ESI, 14)를 확인한다.
- 이때, 0x14보다 작으면 문자열을 출력하는 것을 알 수 있다.
- 즉, 0x14(10진수:20)의 값까지 반복되기 때문에 쓰레기 값이 같이 출력되는 것이다.
7. 00401045 주소의 코드(CMP ESI, 14) 수정하기
- 0x14를 0xA(10진수:10) 으로 값을 변경한다.
- 즉, [CMP ESI, 10] 으로 코드를 수정한다.
8. 출력 확인
- “For Code!!” 문자열이 제대로 출력되는 것을 확인할 수 있다.
'2. Reversing (리버싱) > 1) Write UP' 카테고리의 다른 글
[2023.05.20] 씽씽이 활동보고 (0) | 2023.05.26 |
---|---|
[2023.05.13] 씽씽이 활동보고 (0) | 2023.05.19 |
[2023.04.08] 씽씽이 활동보고 (1) | 2023.04.14 |
[2023.04.01] 씽씽이 활동보고 (0) | 2023.04.06 |
[2023.03.21]씽씽이 활동보고 (0) | 2023.03.22 |