5. DLL relocation
• DLL도 PE 파일이다.
• imagebase가 있다.
• 각 DLL은 보통은 주어진 imagebase에 올라온다.
• 같은 DLL을 이용하는 프로세스는 보통 같은 가상 메모리 주소에 DLL을 올린다.
• 하지만 누군가 해당 주소에 DLL을 올렸다면?
• imagebase가 아닌 곳에 재배치 해 주어야 한다.
• 시스템 DLL은 이런 일이 없도록, 서로 겹치지 않게 imagebase가 잡혀 있다.
• 하지만 프로그래머가 임의로 만든 DLL은 이런 일이 생길 수 있다.
6. DLL relocation
• DLL relocation과 관련 있는 PE 헤더도 있다.
• relocation table
• Relocation하면 PE에 하드코딩 된 주소를 바꿔준다.
• 참고
• 프로세스가 생성될 때 EXE파일이 가장 먼저 메모리에 로딩되기 때문에 EXE는 재배치될 일이 없
었다.
• 하지만 ASLR(Address Space Layout Randomization)이 적용되며 EXE도 다른 Imagebase에 올라오게 됐다.
• 시스템 DLL도 고유 imagebase를 가지고 있지만, ASLR기법으로 인해 부팅 때마다 그 주소가 달라진다.
• 지금 당장 고려할 것은 아님
8. DLL injection이란?
• 실행중인 다른 프로세스에 특정 DLL 파일을 강제로 넣는 것
• 프로세스 : 실행중인 프로그램을 의미
• 실행중인 프로그램에 강제로 내가 만든 라이브러리를 넣고, 그 프로그램이 내가 만든 라이브러리에 저장된 코드를 실행하게 만든다.
• 용도
• 소스코드가 없는 프로그램의 기능 개선, 버그 패치
• 메시지 후킹 : windows 메시지를 가로채어 바꾸거나 조작
• API 후킹 : 평범한 API(ex. printf)를 가로채어 바꾸거나 조작
• PC 사용 모니터링 프로그램 (학교 컴퓨터로 게임 못 하게 하기 등)
• 악성코드를 다른 정상적인 프로세스가 실행하도록 함
• 구현 방법
• 크게 세 가지
• 원격 스레드 생성
• 레지스트리 이용
• 메시지 후킹
10. DLL 만들기
왼쪽은 DLL 소스코드이다. DLL 프로젝트에 적는다.
오른쪽은 DLL을 이용하는 코드이다. 보통 과제 할 때 만드는 평범한 프로젝트를 새로 만들고 오른쪽의 코드를 적는다.
11. DLL 만들기 – DLL 파일
DllMain
• Dll이 어떤 프로세스에 최초로 로딩될 경우, 해제될 경우, 스레드가 시작할 경우, 스레드가 끝날 경우에 자동으로 실행된다.
• hinstDLL은 DLL 핸들, fdwReason은 DllMain이 불린 이유이다. lpvReserved는 궁금하면 부록 참고
• 보통 switch문으로 DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH, DLL_THREAD_ATTACH, DLL_THREAD_DETACH의 네 경우를
나누어 반응한다. 이 예제에서는 편의를 위해 DLL_PROCESS_ATTACH만 넣었다.
• 링크 오류가 나면 왼쪽 사진처럼 설정해보자
12. DLL 만들기 – DLL 이용 프로그램
이 코드가 하는 일
• DLL을 불러온다.
• DLL 파일에서, 사용할 함수의 코드를 찾는다.
• 찾은 함수를 이용한다.
• 이런 방식으로 DLL을 사용하는 것을 “명시적 연결(Linking Explicitly)”이라 한다.
13. DLL injection – 원격 스레드를 이용
1. 대상 프로세스의 메모리에 DLL 이름을 저장한다.
2. 대상 프로세스가 DLL 이름을 가지고 LoadLibrary함수를 호출하게 한다.
3. 자동 호출되는 DllMain을 이용하여 대상 프로세스가 임의의 코드를 실행하게
한다.
• 쓰레드를 만드는 함수에 넣는 인자 크기와 LoadLibrary함수가 받는 인자 크기가 같기때문에 가능한 방법이다.
• 같은 방법으로, 함수 인자 크기가 같은 다른 함수를 호출할 수도 있다.
• 시키고 싶은 일을 전부 넣은 DLL을 만들고 실행시키는 게 효과적이므로 쓰레드 생성 기법은 DLL injection에 많이 쓰인다.
17. DLLinjection–원격스레드를이용–대상프로세스에게 인젝션하는 코드
메인 함수
1. 메인 함수 인자로 프로세스 식별자(pid)와 DLL파일의 경로를 받는다.
2. 인자를 잘 받았다면 InjectDll함수를 호출한다. InjectDll의 인자로 문자로 받은
pid를 숫자로 변환한 것과 DLL 파일 경로 문자열을 건네 준다.
• 메인 함수가 _tmain이면 컴파일 설정으로 유니코드 기능이 설정되어 있다면
유니코드를 인자로 받는 코드를, 유니코드가 꺼져 있으면 char형 인수를 받는
코드를 만든다. 이 부분이 궁금하면 부록을 참고!
18. DLLinjection–원격스레드를이용–대상프로세스에게 인젝션하는 코드
• 인자로 받은 DLL 파일의 경로 문자열의 길이를 구한다. 거기에 자료형의
크기만큼 곱한다. (유니코드는 16bit(2 byte)이기 때문)
• 후에 대상 프로세스의 메모리에 DLL 파일 경로를 저장하게 할 것이므로 확보할
버퍼 크기를 측정했다.
19. DLLinjection–원격스레드를이용–대상프로세스에게 인젝션하는 코드
• 인자로 받은 pid를 이용하여 대상 프로세스의 핸들을 구한다. 핸들을 이용하여
대상 프로세스에게 원하는 작업을 시킬 수 있다.
• 인자를 통해 권한설정 등을 할 수 있다. 해당 핸들이 가지고 있는 권한에 따라
할 수 있는 일의 범위가 결정된다.
• OpenProcess 함수에 대해 궁금하다면 부록 참고
20. DLLinjection–원격스레드를이용–대상프로세스에게 인젝션하는 코드
• 대상 프로세스의 가상메모리 영역에 메모리 공간을 확보한다.
• 위에서 구한 버퍼 사이즈만큼의 공간을 확보한다.
• 확보한 메모리의 시작 주소는 pRemoteBuf에 저장된다.
• VirtualAllocEx 함수가 궁금하다면 부록 참고
• 위에서 확보한 메모리에 DLL 파일 경로를 대상 프로세스의 메모리에 저장한다.
• WriteProcessMemory 함수가 궁금하다면 부록 참고
21. DLLinjection–원격스레드를이용–대상프로세스에게 인젝션하는 코드
• 위에서 저장한 DLL 파일 경로를 이용하여 대상 프로세스가 DLL을 로드 하도록
시킬 것이다.
• 그러기 위해서 LoadLibrary함수의 주소를 알아내고 있다.
• LoadLibrary함수는 kernel32.dll에 있는 함수이다. kernel32.dll은 windows OS가
제공하는 DLL이다. 이 DLL은 프로세스마다 같은 주소에 로딩되기 때문에
본인(이 프로그램)에서의 주소를 구해도 대상 프로세스에서의 주소와 같은
값을 얻을 수 있다.
22. DLLinjection–원격스레드를이용–대상프로세스에게 인젝션하는 코드
• 대상 프로세스에게 원격으로 스레드를 생성했다. 그 스레드는 LoadLibrary함수를
수행한다.
• CreateRemoteThread 함수에 인자로 넣는, 만들 스레드의 함수 인자로 넣을
인자의 크기가 4바이트, LoadLibrary함수의 인자 크기도 4바이트이기 때문에
스레드를 이용하여 호출할 수 있다.
• CreateRemoteThread함수가 궁금하다면 부록 참고
23. DLL injection – 원격 스레드를 이용
• Process Explorer로 대상 프로그램의 pid를 찾았다. (작업
관리자로도 가능하다)
• 아래 창은 해당 프로세스가 쓰고있는 DLL 목록이다.
• 프로그램이 보호기법을 쓸 수 있으므로 되도록 만만하고
오래되어 보이는 프로그램에게 실험해보자. (보호기법을
쓰는 프로그램에게는 안 먹힌다.)
24. DLL injection – 원격 스레드를 이용
• 콘솔창에서 pid와 dll파일의 경로를 입력 값으로 넣어 실행했다.
• 절대경로를 써야함에 주의!!!!!!!!!!!!!!!!!
• DllMain에서 호출하는 함수가 잘 불려서 내가 만든 MessageBox가
호출되었다.
• Process Explorer로 PEiD 프로세서가 내가 만든 dll을 사용하고 있음을
확인할 수 있다.
25. DLL injection – 원격 스레드를 이용 – 디버깅하기
• DLL injection을 디버깅하기 위해서는 올리 디버거2 를 써야 잘 된다.
• Injection할 대상 프로그램을 실행한 뒤 디버거를 attach한다.
26. DLL injection – 원격 스레드를 이용 – 디버깅하기
• Options의 Events에서 Pause on new module(DLL)을 체크한다.
• DLL이 새로 로딩될 때 프로그램을 멈춰준다.
27. DLL injection – 원격 스레드를 이용 – 디버깅하기
• F9로 프로그램을 실행해두고 DLL injection을 실행하면 올리 디버거가
어느 코드에서 멈춘다.
• 이 곳은 내가 만든 DLL 코드가 아니다. DLL을 로드하기 위해서 그
DLL이 사용하는 또 다른 DLL을 로딩하는 과정에서 로딩된 것이다.
• 내 DLL이 로딩될 때까지 진행한다. (F9)
28. DLL injection – 원격 스레드를 이용 – 디버깅하기
• 내가 만든 DLL로 들어왔다. 이제 디버깅하면 된다.
• Options에서 Pause on new module(DLL)을 해제한다. (더이상 걸리면
귀찮으니까)
29. DLL injection – 레지스트리 이용
1. 레지스트리에 DLL을 등록
2. 재부팅 하면 실행되는 모든 프로세스에 해당 DLL을 인젝션 해 줌
재부팅 안 해도, 설정 후 새로 실행한 프로그램에는 인젝션이 된다.
• 엄밀히 말 하면 User32.dll이 프로세스에 로딩될 때 해당 레지스트리 값이 있으면 LoadLibrary() API를 호출하여 로딩 하는 것
• 따라서 모든 프로세스는 아니고, User32.dll을 이용하는 프로세스에만 로딩 해 줌
• User32.dll은 windows에서 제공하는 라이브러리이며, GUI 프로그램에서 필수로 사용하는 라이브러리이다.
• 이 방법은 윈도우 높은 버전에서는 잘 안 통한다... XP에 실습해보자.
30. DLL injection – 레지스트리 이용
• 레지스트리란?
• Windows에서 설정과 선택 항목을 담고있는 데이터베이스
• 모든 하드웨어, OS 소프트웨어, 사용자 어플리케이션, 사용자 PC 선호도 등 각종 설정이 들
어있다.
• 제어판 설정, 프로그램의 등록 여부 등도 이곳에 저장되곤 한다.
31. • 레지스트리에 등록하는 방법은 모든 User32.dll을
이용하는 프로그램에 DLL을 올리므로, 특정
프로그램을 실행했을 때만 반응하도록 조건을 넣은
DLL을 만들었다.
32. DLL injection – 레지스트리 이용
• 실행에 regedit을 입력하여 레지스트리 편집기를 연다.
• 맨 위 상자에 써진 경로로 들어간다.
33. DLL injection – 레지스트리 이용
• AppInit_DLLs 항목에 원하는 DLL 경로 문자열을 쓴다.
• LoadAppInit_DLLs 항목을 1로 설정한다.
• XP에는 없음.
34. DLL injection – 레지스트리 이용
• 재부팅 후 Process Explorer로 DLL을
검색해 보았다.
• 자동으로 injection되어 있다.
35. DLL injection – 레지스트리 이용
• 대상 프로그램이었던 PEiD를 실행한
뒤 파일을 저장한 경로에 가 보았다.
• 잘 저장된 것을 확인할 수 있다.
36. DLL injection – 메시지 후킹을 이용
• 메시지란?
• 운영체제가 프로그램의 외부 또는 내부에 변화가 생겼음을 해당 프로그램에게 알리기 위한
개념
• Window 운영체제에서 실행되는 대부분의 응용 프로그램은 메시지 구동 구조
로 동작한다.
• 대부분의 윈도우 응용 프로그램은 순차적으로 실행되지 않고, 어떤 메시지를 받는가에 따
라 코드의 실행 순서가 달라진다.
• Ex) 마우스 클릭 입력이 들어오면 마우스 클릭에 반응하는 코드를, 키보드 입력이 들어오면 키보드
입력 반응하는 코드를 실행한다.
37. DLL injection – 메시지 후킹을 이용
• 이벤트가 발생하면 OS가 관리하는 시스템 메시지 큐
에 들어간다.
• 각각의 응용 프로그램은 운영체제로부터 독립적인, 자
신만의 큐를 가진다.
• 자신이 받은 메시지들이 저장되어 있음
• 운영체제는 시스템 메시지 큐에 저장된 메시지를 적절
한 응용 프로그램 메시지 큐에 보낸다.
• 각각의 응용 프로그램은 자신의 메시지 큐에서 메시지
를 꺼내 처리하고, 메시지가 없으면 대기한다.
38. DLL injection – 메시지 후킹을 이용
• 훅, 후킹이란?
• Ex) 중요한 시설이 있다. 3중으로 경비 초소를 설치했다. 내부로 들어가기 위해서는 3군데의 경비
초소에서 검문 절차를 거쳐야 한다. 만약 스파이가 중간에 몰래 경비초소를 하나 추가한다면, 이
곳을 통과하는 사람들은 아무 의심 없이 동일한 검문 절차를 밟을 것이다. 스파이는 중간에 앉아
서 오가는 사람들의 정보를 얻을 수 있다.
• 여기서 가짜 초소를 설치하는 일을 훅을 건다고 하고, 실제로 정보를 엿보거나 조작하는 행위를 후킹이
라 한다.
• 즉, 메시지 후킹이란 메시지를 엿보거나 조작하는 것이다.
39. DLL injection – 메시지 후킹을 이용
• OS는 이벤트가 발생하면 어떤 응용 프로그램에서 이벤트가 발생했는지 파악하고, 해당 응용프로램의
큐에 넣는다.
• 그 사이에 메시지 훅이 설치되었다면 응용 프로그램보다 먼저 메시지를 받아볼 수 있다.
• 메시지 자체의 변경, 메시지 삭제도 가능하다.
• 훅 기능은 Windows OS에서 제공하는 기본 기능이다.
• 훅은 여러 개 설치될 수 있다.
• 최근에 설치된 것부터 순서대로 호출되기 때문에 훅 체인이라고 말 한다.
40. DLL injection – 메시지 후킹을 이용
• SetWindowsHookEx함수
• Windows API이다.
• 함수 인자
• idHook : 어떤 종류의 프로시저에 Hook 할 것인지 대한 변수
• 어떤 이벤트에 대한 훅인지
• lpfn : 운영체제가 호출해 줄 콜백 함수, DLL 내부에 존재하는 hook 프로시저
• Call back 함수
• 응용 프로그램이 함수를 call하는 것이 아니라, 특정 조건이 되면 시스템이 응용 프로그램에게 함수를 수행할 것을 요청하는 함수.
• 이벤트가 발생했을 때 불릴 함수
• hMod : hook 프로시저가 속해 있는 DLL 핸들 값
• Injection 관점에서 본다면, injection할 DLL 핸들
• dwThreadId : hook을 걸고 싶은 쓰레드의 ID 값
• 0을 넣으면 실행중인, 그리고 향후 실행될 모든 프로세스에 영향을 미친다.
• 직접적으로 DLL injection을 하기보다는, call back함수를 등록하기 위해 DLL을 이용하면서 자연스럽게 injection
되는 것이다.
41. DLL injection – 메시지 후킹을 이용
1. 메시지 훅을 설치한다.
2. 특정 이벤트가 발생하면 그 이벤트의 주인인 프로세스에 DLL이 injection되고
callback 함수가 호출된다.
3. Callback함수를 통해 원하는 작업을 수행한다.
• XP, windows7, windows8.1에서는 됐다. windows 10에서는 제대로 작동하지 않는다.
44. • 후킹을 시작하는 프로그램이다.
• argv[1]로 injection할 DLL 경로를 넣는다.
• 이 EXE를 실행하면 훅을 걸고, q를 이 프로그램에 입력할 때까지
기다린다.
45. DLL injection – PE 패치를 이용
1. IDT 수정
2. INT 수정
3. IAT 수정
• 엄밀히 말 해서 DLL injection은 아니지만, 원래 이용하지 않던 DLL을 강제로 넣는다는 관점에서 유사하다.
• 직접 PE 파일을 수정해서, 별도의 인젝션 과정 없이 프로세스가 시작할 때마다 알아서 DLL을 로딩 하도록 만든다.
• 일종의 크랙
46. DLL injection – PE 패치를 이용
• 이용할 DLL 코드
• PE 파일의 import 테이블에
적을 함수가 필요하므로
더미 함수를 하나 만들었다.
47. DLL injection – PE 패치를 이용
• 앞으로 수정할 Import table의
위치와 크기를 확인하자.
• PEView의 설정에서 RVA
보기로 했다. 주소를 보고
14264를 찾아가보자.
48. DLL injection – PE 패치를 이용
• 찾았다면 다시 RAW로 바꾸자. 이제 헥사 에디터에서
찾기 쉽겠다.
• FC64를 찾아가보자.
49. DLL injection – PE 패치를 이용
• 이 부분이 IDT영역이다.
• 바로 연결되어 유의미한 데이터가 있다.
• 뒤로 밀고 추가한다면 아래에 있던
데이터들을 매핑한 게 전부 엉망이
된다.
• IDT를 통째로 옮기자!
• 옮기고 나서 데이터 테이블의 IDT
시작 위치를 바꿔주면 된다.
• 이동 할만한 장소
• 파일의 NULL 패딩 부분
• 파일 마지막 섹션의 크기를 늘림
• 파일 끝에 새로운 섹션을 추가함
50. DLL injection – PE 패치를 이용
• 자리가 부족해 보인다.
• 어차피 마지막 섹션이니 크기를 늘리자!
51. DLL injection – PE 패치를 이용
• IDT를 아래 붙여 넣었다.
• IDT의 위치가 바뀌었으니 데이터 디렉토리에서
IMPORT Table의 Virtual Address를 바꿔준다.
• 10770은 RVA로 얼마?
• 014D70
• 리틀 엔디안으로 704D0100
52. DLL injection – PE 패치를 이용
• 원래 IDT가 있던 부분은 굳이 바꾸지 않아도 되지만 그냥 0으로 채웠다.
53. DLL injection – PE 패치를 이용
• 파일에 추가할 우리의 DLL에 대한 정보를 IDT에 추가한다.
• INT는 바로 밑에 쓸 거다. OriginalFirstThunk는 일단 보류.
• TimeDateStamp는 0
• ForwarderChain은 0
• Name은 뒤에 쓸 것
• FirstThunk도 뒤에 쓸 것
54. DLL injection – PE 패치를 이용
• 마지막을 가리키는 NULL배열을 추가한다.
• INT를 추가한다.
• 배열 마지막 가리키는 NULL도 채워야 한다.
57. DLL injection – PE 패치를 이용
• 각각의 위치에 맞게 RVA 값을 설정한다.
• 010824 -> 014E24 이므로 originalfirstthunk는 리틀 엔디안 244E0100
• 01082C -> 014E2C 이므로 AddressOfData는 리틀엔디안 2C4E0100
• 010834 -> 014E34 이므로 Name은 리틀엔디안 344E0100
• 010840 -> 014E40 이므로 FirstThunk는 리틀엔디안 404E0100
• IAT 값은 상관 없지만 보통 INT와 같게 하므로 리틀엔디안 2C4E0100
59. DLL injection – PE 패치를 이용
• 크기가 커졌기 때문에 section 크기를
조정해 준다.
• 섹션 시작 위치는 FA00, 내용이
끝나는 위치는 10847이므로 크기는
E48이다.
• SizeOfRawData는 filealignment로
roundup한 크기이므로 파일 맨
끝에서 시작을 빼면 1000이다.
60. DLL injection – PE 패치를 이용
• Idata도 initialized data에 속하기
때문에 200 늘려준다.
• 크기를 늘려도 섹션 alignment가
적용된 값보다는 작기 때문에
sizeofimage는 그대로이다.
61. DLL injection – PE 패치를 이용
• 마지막으로 IAT에 쓰기 권한을
주어야 한다.
• 기존 IAT는 dataderectory에서
잡히기 때문에 섹션에 쓰기
권한을 따로 주지 않아도
됐지만 추가한 IAT는 따로
주어야 한다.
• 아니면 기존 IAT와
합쳐야 하는데, 자리가
없어서 하지 않았다.
68. DLL ejection 실습
• DLL이 빠진 모습을
볼 수 있다.
• DLL에 프로세스
detach시 반응을
넣어두면 더 잘 볼
수 있다.
69. Codeengn
• 10번 - 다른 종류의 패킹을 풀어보자
• 12번
• 13번 – C#은 올리 디버거에서 제대로 안 돌아간다.
• C#은 자바처럼 플랫폼 위에서 돈다. .NET어셈블리 형태로 컴파일 된다.
• 대신 C#같은 .NET언어는 원시 코드를 생성하기 매우 쉽다.
• .NET Reflector 이용
• 11번은 출제 오류로, 9번과 똑같다. 넘어 감.
72. 참고 사이트
• VirtualAllocEx
• http://ezbeat.tistory.com/177
• https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa366890(v=vs.85).aspx
• WriteProcessMemory
• http://woosunbi.tistory.com/23
• https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms681674(v=vs.85).aspx
• CreateRemoteThread
• https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms682437(v=vs.85).aspx
• http://banananmilk.tistory.com/6
• http://woosunbi.tistory.com/33
• 원격 스레드를 이용한 방식에 대한 자세한 설명
• http://blog.naver.com/PostView.nhn?blogId=shw20319&logNo=20164830013