Инструменты:
- FASM (или любой ассемблер с возможностью создания .bin файлов - fasm, nasm, yasm, etc).
- Python, версии 2.5-2.7, в т.ч. IronPython.
- Библиотека pefile. (работает только с Python'ом 2.5-2.7).
- Любое средство позволяющее убедиться что в файле есть место под патч и нужные импорты.
""" EXE file path example, using pefile library by Ero Carrera (http://code.google.com/p/pefile/) and FASM compiler (http://flatassembler.net/) """ import os import tempfile import pefile # file to patch FILE_NAME = 'some.exe' # we can't know patch size before we compile it, so we should define it before MAX_PATCH_SIZE = 0x80 # path to FASM without backslash, like 'c:\fasm' FASM = '%FASM%' TEMP_FILENAME = tempfile.gettempdir() + '\\patch' pe = pefile.PE(FILE_NAME) text = pe.sections[0] textFileSize = text.SizeOfRawData + ( 0x1FF - (text.SizeOfRawData + 0x1FF) & 0x1FF) # aligned by 0x200 patchRVA = text.VirtualAddress + textFileSize - MAX_PATCH_SIZE k32imp = (entry.imports for entry in pe.DIRECTORY_ENTRY_IMPORT if entry.dll.lower().startswith('kernel32')).next() def get_imp_va(funcName): return hex((imp.address for imp in k32imp if imp.name == funcName).next()) asmFile = open(TEMP_FILENAME + '.asm ', 'w') asmFile.write('''; THIS CODE WAS GENERATED BY SCRIPT use32 label _LoadLibrary dword at ''' + get_imp_va('LoadLibraryA') + ''' label _FindFirstFile dword at ''' + get_imp_va('FindFirstFileA') + ''' label _FindNextFile dword at ''' + get_imp_va('FindNextFileA') + ''' label _OriginalEntryPoint at ''' + hex( pe.OPTIONAL_HEADER.AddressOfEntryPoint +pe.OPTIONAL_HEADER.ImageBase) + ''' include "''' + FASM + '''\include\win32a.inc" org ''' + hex(pe.OPTIONAL_HEADER.ImageBase + patchRVA) + ''' align 16 ; NewEntryPoint call LoadPlugins call _OriginalEntryPoint ret mask db "*.plgn", 0 align 16 proc LoadPlugins uses edi local findData:WIN32_FIND_DATA lea eax, [findData] invoke _FindFirstFile, mask, eax mov edi, eax test eax, eax jnz load_loo ret load_loo: lea eax, [findData.cFileName] invoke _LoadLibrary, eax lea eax, [findData] invoke _FindNextFile, edi, eax test eax, eax jnz load_loo ret endp ''') asmFile.close() err = os.system(FASM + '\\fasm.exe ' + TEMP_FILENAME + '.asm ' + TEMP_FILENAME + '.bin') os.remove(TEMP_FILENAME + '.asm') if err == 0: print "\nCompiled OK. Patching." binfile = open(TEMP_FILENAME + '.bin', 'rb') pe.set_bytes_at_rva(patchRVA, binfile.read()) pe.OPTIONAL_HEADER.AddressOfEntryPoint = patchRVA pe.write(FILE_NAME) binfile.close() os.remove(TEMP_FILENAME + '.bin') print "All done." os.system("pause")
Замечания по коду:
- Код совместим с Python 2.5 по этому там нет with.
- Код совместим с IronPython по этому там явно вызываются close() для файлов. В обычном пайтоне можно писать
pe.set_bytes_at_rva(patchRVA, open(TEMP_FILENAME + '.bin', 'rb').read())
хендлы закроются сами. - Разумеется это простейший пример, для .exe файла без релоков, у которого уже импортированы нужные функции, впрочем с помощью pefile можно решать и более сложные задачи.
- Запись в конец секции плохо выглядит с точки зрения антивирусов. По хорошему надо как минимум патчить сразу за концом оригинального кода, чтобы не было большого разрыва.
No comments:
Post a Comment