https://ddddhkim.github.io/project/2017/03/20/Python-UPX_UNPACK.py.html
ddddhkim형과 같이 upx언패커를 만들었는데 아주 쉬울줄 알았는데 덤프가 가장 어려웠다
IAT rebuild때문에 조금 걸렸는데 이부분은 나중에 다시 좀 더 수정해야겠다.
(실수를 하나 했는데 모든 IAT가 idata섹션에만 있는거 아니라서 DataDirectory안에 있는 import table 관련해서 좀 더 수정해야할거 같다.)
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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | import pefile from struct import * from pydbg import * from pydbg.defines import * def signature(dbg): sig = dbg.read_process_memory(ep+6, 2) if sig.encode('hex') == "8dbe": print "Packing with UPX!!" else: pass def OEP(dbg): global num disasm = dbg.disasm(dbg.exception_address) if disasm.startswith("jmp"): num = True dbg.single_step(True) else: dbg.single_step(True) return DBG_CONTINUE def entry_point(dbg): API(dbg) disasm = dbg.disasm(dbg.exception_address) esp = dbg.context.Esp dbg.bp_set_hw(esp, 4, HW_ACCESS, handler=OEP, restore=False) return DBG_CONTINUE def single_step(dbg): global num disasm = dbg.disasm(dbg.exception_address) if 0x70000000 < int(dbg.exception_address): pass elif disasm.startswith("jmp"): num = True dbg.single_step(True) elif num: print "[*] Find OEP: " + hex(dbg.exception_address) dbg.bp_del_all() upx(dbg) else: dbg.single_step(True) return DBG_CONTINUE def API(dbg): loadlibA = dbg.func_resolve("kernel32.dll","LoadLibraryA") getprocaddr = dbg.func_resolve("kernel32.dll","GetProcAddress") dbg.bp_set(loadlibA, handler=LoadLibraryA, restore=True) dbg.bp_set(getprocaddr, handler=GetProcessAddress, restore=True) return DBG_CONTINUE def GetProcessAddress(dbg): global Switch_ global API_Names global NumOfSection esp = dbg.context.Esp api_addr = unpack("<I", dbg.read_process_memory(esp+8, 4))[0] api_name = dbg.get_ascii_string(dbg.read_process_memory(api_addr, 30)) if Switch_ == True: API_Names.append([]) Switch_ = False INDEX = len(API_Names) - 1 # NULL PADDING if len(api_name) % 2 == 0: API_Names[INDEX].append(api_name) else: API_Names[INDEX].append(api_name+'\x00') return DBG_CONTINUE def LoadLibraryA(dbg): global DLL_Names global IAT_DLL_OFFSET global Switch_ Switch_ = True esp = dbg.context.Esp ebx = dbg.context.Ebx dll_addr = unpack("<I", dbg.read_process_memory(esp+4, 4))[0] dll_name = dbg.read_process_memory(dll_addr, 20) dll_name = dbg.get_ascii_string(dll_name) if dll_name.lower().endswith("dll"): INDEX = len(DLL_Names) DLL_Names.append([]) DLL_Names[INDEX].append(dll_name+'\x00') DLL_Names[INDEX].append(ebx) if ebx > IAT_DLL_OFFSET[0]: IAT_DLL_OFFSET[0] = ebx IAT_DLL_OFFSET[1] = INDEX else: pass print INDEX API(dbg) return DBG_CONTINUE def upx(dbg): global DLL_Names global API_Names global IAT_DLL_OFFSET global NumOfSection o = open("dump.exe", "wb") ImageBase = pe.OPTIONAL_HEADER.ImageBase base = int(ImageBase + pe.sections[1].VirtualAddress) SizeOfDOSHeader = unpack("<I", dbg.read_process_memory(ImageBase+0x3c, 4))[0] DOS_Header = dbg.read_process_memory(ImageBase, SizeOfDOSHeader) text = dbg.read_process_memory(ImageBase, 0x300) add = text.encode('hex').find("50450000") DOS_Header = dbg.read_process_memory(ImageBase, (add/2)) print "[*] DOS Header!!" base1 = int(ImageBase + pe.sections[1].VirtualAddress) length = int(pe.sections[1].Misc_VirtualSize) NT = dbg.read_process_memory(base1, length) add = NT.encode('hex').find("50450000") NT_Header = dbg.read_process_memory(base1+(add/2), 0xf8) NumOfSection = unpack("<H", NT_Header[6:8])[0] SizeOfPEHeader = unpack("<I", NT_Header[0x54:0x58])[0] print "[*] NT Header!!" Section = dbg.read_process_memory(base1+(add/2)+0xf8, 0x28 * NumOfSection) padding = SizeOfPEHeader-(len(DOS_Header) + len(NT_Header) + len(Section)) print "[*] Section Header!!" DataOfSection = '' for x in range(NumOfSection): index = x * 0x28 VV_Addr = unpack("<I", Section[index+12:index+16])[0] V_Addr = ImageBase + VV_Addr V_Size = unpack("<I", Section[index+16:index+20])[0] Section_Name = Section[index:index+6] Section_Name = dbg.get_ascii_string(Section_Name) # IAT RECOVERY if Section_Name == ".idata": IAT = "\x00" * V_Size NumOfAPI = [len(x) for x in API_Names] NumOfDLL = len(DLL_Names) IAT_DLL_OFFSET = IAT_DLL_OFFSET[0] - (V_Addr - (NumOfAPI[IAT_DLL_OFFSET[1]] + 1) * 4) # IMPORT DLL Names IMPORT_DLL_Names = "" IMPORT_DLL_Names += "".join(["".join(DLL_Names[x][0]) for x in range(NumOfDLL)]) IMPORT_DLL_Names += "\x00" # IMPORT Hints/Names IMPORT_Hints = "\x00\x00" IMPORT_Hints += "\x00\x00".join(["\x00\x00".join(y) for y in API_Names]) # LenOfImport LenOfImport = len(IMPORT_DLL_Names) + len(IMPORT_Hints) # IAT Rebuilding IAT = IAT[:IAT_DLL_OFFSET] + IMPORT_DLL_Names + IMPORT_Hints + IAT[IAT_DLL_OFFSET+LenOfImport:] IAT_DLL_OFFSET += VV_Addr # IMPORT_Directory_Talbe for x in range(NumOfDLL): IAT = IAT[:(0x14*x)+0xc] + pack("<I", IAT_DLL_OFFSET) + pack("<I", DLL_Names[x][1]-ImageBase) + IAT[(0x14*x)+0x14:] IAT_DLL_OFFSET += len(DLL_Names[x][0]) API_RVA = IAT_DLL_OFFSET + 1 # IMPORT_Address_Table for x in range(NumOfDLL): # Int IMPORT_Address_Table = "" for y in range(NumOfAPI[x]): # List IMPORT_Address_Table += pack("<I", API_RVA) API_RVA += len(API_Names[x][y]) + 2 INDEX = DLL_Names[x][1] - V_Addr INDEX_ = INDEX + len(IMPORT_Address_Table) + 4 IAT = IAT[:INDEX] + IMPORT_Address_Table + "\x00\x00\x00\x00" + IAT[INDEX_:] DataOfSection += IAT elif Section_Name == ".rsrc": for rsrc in pe.DIRECTORY_ENTRY_RESOURCE.entries: for entry in rsrc.directory.entries: pass rva = (entry.directory.entries[0].data.struct.OffsetToData) # version size = (entry.directory.entries[0].data.struct.Size) # version size va = pe.sections[2].VirtualAddress # 0x56000 address = rva-va+size rsrc_data = dbg.read_process_memory(V_Addr, V_Size) DataOfSection += dbg.read_process_memory(va+ImageBase, address) + rsrc_data[address:] else: DataOfSection += dbg.read_process_memory(V_Addr, V_Size) o.write(DOS_Header+NT_Header+Section+'\x00'*padding+DataOfSection) o.close() print "Success!!" return DBG_CONTINUE Switch_ = True DLL_Names = [] IAT_DLL_OFFSET = [0, 0] API_Names = [] num = False target = raw_input("FileName: ") pe = pefile.PE(target) ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint + pe.OPTIONAL_HEADER.ImageBase dbg = pydbg() dbg.set_callback(EXCEPTION_SINGLE_STEP, single_step) dbg.load(target) signature(dbg) dbg.bp_set(ep+1, handler=entry_point, restore=False) dbg.run() | cs |
'HACK > Reversing' 카테고리의 다른 글
DLL 인젝션 (1) | 2016.08.07 |
---|---|
PE View path (0) | 2016.02.02 |
MSDN ANNOTATIONS (3) | 2016.01.11 |