아 오늘 좀 궁금증이 풀리네요.
아래는 오늘 끄적거린 공부 내용입니다.
----------------------------------------------
사용도구
디버거 : OllyDbg 1.10
플러그인 : OllyAdvanced v1.25
덤프 : LordPE Deluxe
임포트 수정 : ImpREC 1.6f
코드 스플라이싱 : ArmInline 0.96f
기타 : Dll Loader.exe, VC++
도구같은 LoadDll
모든 DLL에는 DLL이 로드될 때 실행되는 EntryPoint가 존재한다. 이 루틴은 많은 RCE 코더들이 다른 프로세스의 메모리에 DLL을 inject할 때 hooking과 pactching을 하기 위해 사용된다. 일반적으로 다시 실행되지 않는다. 또한 이 루틴은 간단한 초기화 또는 준비에 사용되는데, 이는 코더들에 따라 달라진다. 이 코드는 입력값 없이 실행되며, DLL의 로딩이 성공적으로 실행되었는지 알기 위해 0 또는 1을 반환한다.
이 루틴은 Armadillo가 언패킹 절차를 수행할 때 사용된다. 본래 DLL의 export 함수들은
아르마딜로는 DLL을 보호할 때 뮤텍스들을 많이 사용하지 않는다. 이는 부모 프로세스를 검사할 필요가 없기 때문이다. 대신 "XXXXXXXX:SIMULATEEXPIRED'라는 뮤텍스를 바로 실행한다. 이 뮤텍스는 아르마딜로 프로텍트 GUI에서 기간 만료를 체크하기 위해 스스로 만든 것이다. 이 뮤텍스가 사용가능하고 오픈된다면 아르마딜로에 의해 보호받는 어플리케이션은 기간이 만료된 버전처럼 행동한다. 레지스트리키에 저장되는 만료 상태와 TMP/ADS 파일들을 생성하지 않는다. 이 점이 우리가 처음 공격할 목표이다. 언패킹 단계를 수행할 동안 DLL을 잡고 공격할 수 있다. OpenMutexA에 중단점을 걸고, 우리는 루틴의 끝에 있을 필요가 없다. 우리는 이 루틴이 NULL을 반환할 것을 알고 우리에게 반환값이 중요하지 않다는 것을 알기 때문이다. 단지 dll에서 우리가 멈출 수 있는 위치이다.
- DLL 로딩 후 OpenMutexA에 중단점 설정 및 실행
실행 후 OpenMutexA에 걸린 중단점을 없앤다. 그 후 우리는 2개의 중단점을 더 설정할 것이다. 첫번째 중단점은 VitualProtect에 세울 것이다. 이는 아르마딜로가 보호받는 App/Dll의 섹션에 언패킹하기 전 메모리 권한을 바꾸기 때문이다. 이는 IAT 초기화 부분에 닿기 전에 잡을 수 있는 방법이다. 우리가 전에 이 부분에 중단점을 설정하지 않은 이유? 여기엔 두 가지 이유가 있다.
1. Security.dll(Virtual dll)이 초기화되지 않았기 때문에 우리는 원하는 것 대신 이 부분을 잡게된다.
2. 아르마딜로의 중단점 탐지가 수행되기 때문에 지금 수행하는게 좋다.
두번째 중단점은 이 API의 첫번째 5바이트의 어느 부분에든 세워둔다면 탐지될 것이다. 그래서 우리는 이 호출의 반환 부분에 중단점을 세울 것이다. (또는 하드웨어/메모리 브레이크 포인트를 걸어도 된다.) 이 예제에서는 하드웨어 중단점을 사용할 것이다. 지금 VirtualAlloc에 중단점을 세우고 Shift+F9를 통해 실행해라.
아르마딜로의 예전 버전에서는 msvcrt.time이 Code Splicing을 검사하기 위해 중단점으로 사용될 수 있었다. 이는 아르마딜로가 이 API를 splice들을 초기화하기 위해 호출하기 때문이었다. 5.xx 버전에서 이 함수는 호출되지 않는다. VirtaulAlloc의 중단점에 거리면 아르마딜로가 수많은 바이트를 요청하는 것을 볼 수 있다. 버전 4.40.0240은 1000h를 요청한다. 이는 Code Splicing이 존재하거나 존재하지 않거나 행해진다. 버전 5.xx는 Code Splicing이 사용되지 않으면 이를 사용하지 않는다.
대상 dll은 Code Splicing을 사용하기 때문에 우리의 하드웨어 중단점은 VirtualAlloc에 걸리고 그 호출 인자에는 요청받은 주소가 있다.
요청받은 주소는 중요하지 않다. 왜냐면 우리는 우리가 선택한 주소로 그 주소를 변경할 것이기 때문이다. Dll 이미지의 끝에 가까운 주소로. 이 변경은 섹션을 디스크로 덤핑하는 것이며, 언패킹된 dll에 쉽고 간결하게 붙일 수 있다. 우리가 선택한 주소로 메모리를 선택한다면 2 가지 결과물이 가능하다.
1. 윈도우 로더가 섹션이 계속 남길 필요하기 때문에 윈도우에 의해 로드될 실행 가능한 이미지가 매우 커질 것이다.
2. 섹션은 dll의 ImageBase아래에 위치할 것이다. 이 위치는 덤프된 이미지에 붙을 때 이미지를 invalid하게 할 것이다. 우리는 ImageBase를 바꿀 수 있고 RVA를 수정할 수 있다. 하지만 이는 매우 귀찮은 일이다.
사용되지 않는 아르마딜로 섹션에 splice를 리다이렉팅하는 보통의 방법은 이 dll에 적용하지 못한다. 섹션이 20000h 사이즈이기 때문에. Text1 과 .pdata 섹션은 더 작아서 안된다. 두 섹션을 덤프 섹션을 집어넣기 위해, .text1 섹션은 여전히 필요한 코드들이 담겨 있고 .pdata 섹션은 dll의 encrypt된 내용이 담겨있다.(.pdata섹션도 사용하지 못한다.) 우리는 splice 를 수정하기 위해 어떻게 ArmInline을 사용하는지 알 것이다. 하지만 맨 처음 우리는 위의 두 접근 방법을 배워볼 것이다. splice들을 덤프에 붙이기 위해.
다시 작업으로 돌아가서, 우리는 이 첫번쨰 VirtualAlloc 호출이 성공하길 원하지 않는다. 그래서 요청받은 주소를 변경할 것이다.
- 요청받은 주소를 0xFFFFFFFF로 변경
0xFFFFFFFF은 invalid 주소로 Alt+F9를 사용하여 유저코드로 돌아온다. 우리는 아르마딜로의 코드로 도착할 것이다. 호출이 성공적인 것을 검사하는 코드로 도착.
다음과 같은 코드로 이동한다.
EAX가 새로 할당할 메모리 영역의 주소를 담게된다.
이 새로 할당되는 메모리 영역을 새로운 섹션으로 잡기 위해 마지막 섹션의 다음 섹션으로 주소를 잡는다.
1F1EC000 + 4C000 = 1F238000
Alignment가 10000이기 때문에 1F240000h로 새 주소를 잡는다.
- EAX 1F240000h로 변경 at 0x00B98988
- VirtualAlloc 함수 호출
VirtualAlloc 함수 호출 이후 EAX 값이 NULL인지 검사한다. NULL이면 할당 실패. 입력 주소이면 할당 성공. 이후 중단점을 지우면 VirtualProtect에만 중단점이 남게 된다. (나머지 중단점 제거)
여기서 VirtualProtect의 중단점을 잠시 없애고 LoadLibraryA에 중단점을 걸고 실행한다. 이것은 IAT 초기화 루틴이 리다이렉션되지 않기 위해 브레이크를 거는 방법이다. 또다른 이유는 IAT Elimination을 검사하기 위한 코드의 일부분에 접근할 수 있기 때문이다. 이 DLL이 IAT Elimination을 사용하지 않을지라도, 네가 IAT Elimination을 검사할 수 있고 false IAT가 어디에서 끝나는지 변경할 수 있는 쉬운 방법이다. ArmInline은 대단한 도구인데, 이 도구는 덤핑하기 위해 이동된 import들을 재배치하게 해준다. 하지만 IAT가 풀리기전에 IAT를 리다이렉트할 수 있다면 사용할 필요는 없다.
LoadLibraryA에 중단점을 걸고 실행한다. 이후 return until user code로 아르마딜로의 코드로 복귀한다.
아르마딜로가 적용된 다른 대상을 목표로 할 시에 그들이 임포트하는 다른 라이브러리들을 로드하기 때문에 라이브러리의 이름은 중요하지 않다. 중요한 건 우리가 도착한 코드이다. 만약 우리가 GeProcAddress를 호출하는 것을 본다면 올바른 위치가 아니다. 다시 실행하여 올바른 위치로 올 수 있다.
이 코드에서 아르마딜로 5.xx와 아르마딜로 3.78 - 4.xx는 다른 내용을 담고 있다. ( 이 부분은 네가 몇몇의 파일들을 분석하면 쉽게 인지할 수 있다. ) 또한 3.78 이전 버전들의 내용과도 다르다. 주소들을 네가 정확한 위치에 있는지 확인하려고 사용하지 마라. 파일에 따라 다르고 실행 시 마다 또 다르다. 대신에 return op-code가 있는 코드를 살펴보라. 아르마딜로를 언패킹하는 경험이 쌓이면 정확한 위치에 있다는 것을 알것이다. :-)
나는 정확한 위치가 어딘지 어떻게 아는지에 대해 설명할 수 없다. 경험이 중요하다. 어쨌든 실행가능한 파일과 dll에서 적용되는 방법을 너에게 보여주고 있다. 이 방법은 또한 3.78 이전 버전들과 3.78 - 4.xx 버전까지 적용된다. 이 방법은 또한 단 한번의 실행으로 알 수 있다는 장점이 있다.
이 위치는 IAT 초기화 루틴이 아니다. 하지만 이 루틴은 IAT 초기화 루틴에 의해 호출되는 루틴이다. 따라서 execute until return으로 다음 코드로 넘어간다. LoadLibraryA의 중단점은 제거한다.
EAX를 지역 변수에 저장하며, 성공적으로 라이브러리가 로드되었는지 확인한다. 또 검사한다. 점프 후 또다시 검사하는데 이는 위의 다른 로딩 방법을 수행한 후 확인하는 부분이다.
이후 로드된 라이브러리의 base 주소가 인크립트된 base 주소들의 목록에 있는 주소인지
횽꺼 방송한거 나중에 다시 볼 수 없음?