Хотел продемонстрировать простоту использования IDA Python, но както не попадалась интересной цели. И вот наконец, нашел кое-что интересное:
http://cracklab.ru/f/index.php?action=vthread&forum=6&topic=17494
Автор описывает это так:
"Вот семпл выводящий сообщение. Над исходным бинарем выполнен автоматический ресерч и морфинг, при котором выполнена генерация Gs-серий для линейных блоков http://indy-vx.narod.ru/Temp/GsTest.zip"
Загрузив в GsTest в IDA, можно увидеть интересный способ морфинга бинарного кода с использованием segment override prefix'ов. Выглядит это так:
start proc near
push ebp
mov ebp, esp
add esp, 0FFFFFFD4h
push fs
pop gs
mov eax, large gs:30h
push ds
pop gs
assume gs:_text
mov eax, gs:[eax+0Ch]
push ds
pop gs
mov eax, gs:[eax+0Ch]
push ds
pop gs
mov eax, gs:[eax]
push ds
pop gs
mov ebx, gs:[eax+18h]
push ss
pop gs
assume gs:nothing
mov dword ptr gs:[ebp-10h], 59B88A67h
В OllyDbg это не трассируется, но цель данной заметки совсем в другом - показать, как просто можно получить чистый код из морфированного, используя IDA Python.
Скрипт для каждой ф-ции перечисляет все инструкции, с целью поиска pop gs, затем получает код префикса (в данном ехе используются лишь segment override prefixes), затем в базу данных IDA вносятся изменения( nop's и соответствующие коды префиксов там где юзается gs) для получения чистого кода. Так как у IDA немного едет крыша и она прячет часть кода в assume gs:xxx, в скрипте делается принудительный undefine. После работы скрипта IDA database будет содержать практически готовый код, за исключением нопов. В принципе ничего не мешает сохранить эту базу и сделать вывод уже без нопов.
Конечный результат выглядит так:
401000 push ebp
401001 mov ebp, esp
401003 add esp, 0FFFFFFD4h
40100a mov eax, large fs:30h
401014 mov eax, [eax+0Ch]
40101b mov eax, [eax+0Ch]
401022 mov eax, [eax]
401028 mov ebx, [eax+18h]
40102f mov [ebp+var_10], 59B88A67h
40103a mov [ebp+var_C], 0DB164279h
401045 mov [ebp+var_8], 9E1E35CEh
401050 mov [ebp+var_4], 0
401057 lea eax, [ebp+var_10]
40105a push eax
40105b push 0
40105d push ebx
40105e call sub_401103
По моему вполне читабельно, и скорее всего компилябельно.
Сам скрипт:
from idaapi import *
from idc import *
from idautils import *
def GetPreviousInstructionAddress( address ):
prevInstructionAddress = PrevNotTail( address )
return prevInstructionAddress
def GetNextInstructionAddress( address ):
nextInstructionAddress = NextNotTail( address )
return nextInstructionAddress
def GetSegmentOverridePrefixAndEliminatePush( address ):
nopOpcode = 0x90
if GetMnem( address ) == "push":
if GetOpnd( address, 0 ) == "cs":
PatchByte( address, nopOpcode ) # 0Eh
return nopOpcode
elif GetOpnd( address, 0 ) == "ss":
PatchByte( address, nopOpcode ) # 16h
return nopOpcode
elif GetOpnd( address, 0 ) == "ds":
PatchByte( address, nopOpcode ) # 1Eh
return nopOpcode
elif GetOpnd( address, 0 ) == "es":
PatchByte( address, nopOpcode ) # 06h
return nopOpcode
elif GetOpnd( address, 0 ) == "fs":
PatchWord( address, 0x9090 ) # 0FA0h
return 0x64
elif GetOpnd( address, 0 ) == "gs":
PatchWord( address, 0x9090 ) # 0FA8h
return nopOpcode
else:
return 0
def EliminatePopSegmentOverridePrefix( address ):
PatchWord( address, 0x9090 )
def SetSegmentOverridePrefix( address, segmentOverridePrefix ):
PatchByte( address, segmentOverridePrefix )
def ProcessGs( address ):
prevInstructionAddress = GetPreviousInstructionAddress( address )
segmentOverridePrefix = GetSegmentOverridePrefixAndEliminatePush( prevInstructionAddress )
nextInstructionAddress = GetNextInstructionAddress( address )
MakeUnkn(nextInstructionAddress, DOUNK_SIMPLE)
nextByte = nextInstructionAddress
MakeCode( nextByte + 1 )
SetSegmentOverridePrefix( nextInstructionAddress, segmentOverridePrefix )
def RemoveGsInFunction( functionStart, functionEnd ):
for address in Heads( functionStart, functionEnd ):
if GetMnem( address ) == "pop" and GetOpnd( address, 0 ) == "gs":
ProcessGs( address )
EliminatePopSegmentOverridePrefix( address )
def PostProcessMakeCode( functionStart, functionEnd ):
start = functionStart
end = functionEnd
for address in Heads( functionStart, functionEnd ):
prevByte = address
prevByte = prevByte - 1
MakeUnkn( address, DOUNK_SIMPLE )
MakeCode( start )
#
# entry point
#
ea = ScreenEA()
for func in Functions( SegStart(ea), SegEnd(ea) ):
functionStart = func
functionEnd = FindFuncEnd( functionStart )
RemoveGsInFunction( functionStart, functionEnd )
PostProcessMakeCode( functionStart, functionEnd )
Данный скрипт собранный на коленке за 20 мин, естественно не претендует на generic деобфускатор( в нем не обрабатываются chunks, не убираются jxx следующие друг за другом и т.д., скрипт вобще не содержит никакой обработки control flow ), он лишь показывает, как быстро можно писать обработку бинарного кода, используя IDA Python.
Комментариев нет:
Отправить комментарий