PE파일 구조는 이제 다들 잘 알잖아. 이미지 스위칭만 공부해보자.
이미지 스위칭이란 껍데기는 A프로세스라고 실행되는 것처럼 보이는데 실행되는 것은 B프로세스인 것이다.

요런 개념이라고 생각하면 된다.
이런 이미지 스위칭은 운영체제의 보안이 강화되면서 윈도우즈7부터는 일반 어플리케이션만 가능하다. 노트패드나 계산기 가지고 하면 안된다.
예컨대 우리 눈에는 은행 보안 프로그램처럼 보이는 것들이 있어서 실행해봤는데, 실제로는 뒤에서 다른 불법적인 동작이나 우리 개인정보를 탈취하는 동작을 하고 있을 수 있지.
아니면 노션 같은 앱인 줄 알고 실행했는데 실제론 뒤에서 다른 것 하고 있겠지
실습은 DebugMe3.exe 가지고 하면 된다.
근데 이거 터미널 열어서 debugme 이거 실행하려고 파라미터에 넣으면, 막상 안됨. 아마 Windows11부터는 일반 어플리케이션이라도 이미지 스위칭 조짐이 보이면 안되게 하는 듯.
바로 디버깅으로 넘어가자.
디버거로 열어서 실행하다보면 main 위치까지 온다
main인지 어떻게 알지?
까먹었을 까봐 알려주면. 메인의 스택프레임을 새로 열어주는 것이 메인이겠지.
push ebp
mov ebp,esp
sub esp,~ (esp 끌어올리기)
요런 것들이 있으면 이제 메인프레임인 걸 알겠지.
메인함수를 보면 좀 여러개의 함수와 api를 호출한다.
CALL ~~ 가 많다는 것이지.![[Pasted image 20250313160732.png]]
이런 순서로 호출의 흐름이 이어진다고 보면 된다.
아는 친구들이잖아? 얘네는 넘어가. api후킹이나 dll인젝션할때부터 봐온 애들이야.
책에서는 얘를 알고 싶으면 디버거를 새로 시작해서 call 00401150 SubFunc_1( )로 가라고 한다.
새로 시작하라는 이유
기존 디버거에서 "call SubFunc_1( )"의 주소가 나와있으니까 거기로 바로 점프하라는 거겠지.
이 함수는 크게 두가지 동작이 있다.
알맹이(음흉) 실행 파일을 통째로 메모리에 읽어들이기
- 그럼 메모리의 어느 주소에 이 알맹이 파일의 내용이 저장되어있다.
껍데기 프로세스를 SUSPEND 모드로 생성한다.
CreateProcess( )를 호출하는데, 파라미터에 CREATE_SUSPEND도 들어감.
-서스펜드 모드로 생성해야 껍데기 프로세스 실행을 멈춘 상태에서도 메모리를 조작할 수 있다.
얘가 좀 핵심이래
GetThreadContext( ) API를 호출해서 껍데기의 메인 스레드 컨텍스트를 구한다.
이래야 PEB(process environment block)를 구하기 위해서다. 프로세스의 실제 매핑 주소는 PEB의 Image Base 멤버에 저장되어 있다.
ReadProcessMemory( ) API 호출해서 껍데기 프로세스의 매핑 주소를 구한다.
현재 껍데기 프로세스는 SUSPEND MODE로 생성된 채 정지되어 있는거 기억나지? (SubFunc1 생각해봐)
껍데기가 생성되면 시스템의 PE Loader는 EBX 레지스터 초기값을 PEB 구조체 주소로 설정 ( 이 말이 더 어려워서 이 대사로 이해 못해도 괜찮아)
이렇게 설명하자 자자 들어봐.
1. 내가 구하고 싶은 것 = PEB 구조체 주소
2. 왜 PEB 구조체 주소를 구하고 싶을까? : 거기엔 ImageBase 멤버가 있거든.
3. 그럼 PEB 구조체는 어디에 있을까 = CONTEXT 구조체의 멤버로 있음(DWORD)
4. 그럼 나는 무엇의 주소를 우선 구해야 하겠니? = CONTEXT
이게 이해된다면 이 코드가 좀 눈에 들어온다.

컨텍스트를 구한다=PEB 주소를 구한다
-> PEB에서 ImageBase를 구한다.
이미지베이스 왜 구하냐? 설명할게
위의 코드 다음에 나오는 코드들이 있다. 이건 껍데기 안에 바꿔치기로 넣을 악성 파일의 PE 헤더 정보를 읽어서 ImageBase를 구하는 것이다.
ㄹㅇ 모르겠음.
- EDI 레지스터 = MEM_FILE_REAL_EXE의 주소래.
- 그게 뭔데? -> SubFunc1에서 할당 받은 메모리 주소야.
- 그 주소엔 뭘 위해 할당했지?-> 새 알맹이가 될 악성파일의 내용이 그대로 저장되어 있지.
- 1을 다시 말하면 EDI는 악성 알맹이 파일의 PE 헤더를 가리킨다.
EDI + 3C는 뭔데? 라고 물으면 그... PE 구조 할때 기억나시나여
DOS 헤더 구조체의 e_lfanew 멤버야. 그걸 EAX에 넣는대.
자 그럼 이미지 베이스를 어떻게 구하냐.
이미지 베이스는 IMAGE_OPTIONAL_HEADER에 있었지. 0에서 그 주소까지 가려면 몇을 더해야 할까?
0 + PE 시작 주소까지 + 거기서 부터 NT 헤더 주소까지 + NT헤더에서 0x34만큼 가봐
= 0 + (이건 EDI에 구했지?) + (이건 EAX에 구했지?) + 0x34
그래서 이미지 베이스를 구하는 건 [EDI+EAX+34]이다. 이걸 ECX 정도에 보관하면 여기에 악성 알맹이 파일의 ImageBase를 구할 수 있다.

EAX는 도스 헤더의 e_lfanew라며? 이제 와선 왜 NT헤더 시작을 의미하는데?
-> 맞아 맞아 그건 사실이야.
하지만 e_lfanew는 도스 헤더의 마지막 멤버잖아.
PE의 시작에서 그만큼의 값을 더 해주면 도스헤더가 끝나는 주소잖아.
그럼 그 다음 헤더의 시작 주소니까 NT헤더를 의미한다는거지.
이제 정상처럼 보이는 가짜 껍데기 프로세스의 실제 매핑 주소와 악성 알맹이 프로세스의 이미지베이스를 비교한다.

i) 같다면?
둘의 이미지베이스가 같다는 건 무얼 의미할까
악성 알맹이의 PE Image가 매핑되려는 주소(예:400000)에 이미 껍데기 프로세스의 PE Image가 매핑된거지. 그래서 그대로 악성 알맹이를 매핑하려면 충돌이 발생해.
어떡하지?
먼저 껍데기용 정상 프로세스의 PE Image를 언매핑한다. 그래도 되냐고? 얜 어차피 SUSPEND 상태로 존재하기 때문에 PE Image 언매핑해도 프로세스에 오류가 생기진 않는다.
언매핑 어케하는데;;
ntdll!ZwUnmapViewOfSection( ) API를 써서 해...

ii) 다르면?
뭐 간단해지지? 언매핑도 필요없고
정상 껍데기 프로세스의 가상 메모리공간에 악성프로세스를 위한 공간을 할당해주고 매핑해준다.
PE 로더한테 이 껍데기 프로세스의 PE Image는 악성알맹이의 이미지베이스 주소로 해줘야한다고 알려야 한다.
어케 알리는데;;
정상 껍데기의 PEB의 ImageBase를 변경하면 된다. WriteProcessMemory( ) API 쓰면 돼.

너무 힘드러여ㅛ 이따 쓸게여