Voila keygen
工具: IDA v5.2, gdb
IDA可以用Wine在mac os x上跑起来,或者有两台电脑,一台windows,跑IDA,另一台Mac。
在windows平台中打开ida,加载Voila(Mac OS X binary)
找到的关键地方为:
000A9B8F __VLRegister_registerContinue__


下面再跟进下面的函数:
000AA67A __VLRegister_validateKeyWithInfo_Fortype__
在000AA681执行后,查看ecx:

下面,判断使用什么key

参数nType_C是从下面传进来的.
__text:000A9C0B C7 44 24 0C 00 00 00 00 mov [esp+0B8h+var_AC], 0
看看key:

继续:

注意到上图最上面两行, 两个常数, 为方便起见,就当作是一个int64整数.
跟进_GetSystemInfo
实例化一个SystemState类

进入构造函数 SystemState::SystemState(unsigned char const*, char const*, long long, EValidationType):

如果没有传入上面提到的int64常数,则调用GetSeed函数来生成一个int64.
继续:

SystemState::GetFirstState 用来校验注册码的长度(0x20)和注册码的字符(数字和字母).
再跟进 SystemState::GetState

首先调用SystemState::GetDecryptText,然后对解出来的信息进行校验.
跟进SystemState::GetDecryptText:

取出序列号的最后一个字符,然后找到这个字符在” NIWHSALRMPJ5EKTUYX3012QV67ZGF984”中的位置(第一个字符位置为0),设为LastCharIndex。
下面再从注册码中的LastCharIndex开始,取5个字符,设为Part_5,将剩余的26个字符,合并为Part_26

再来看看SystemState::GenerateEncryptedPart
这个函数先将注册码分割为两部分,再将注册码用其在两个字符串中的位置所代替。
偶数字符从 SystemState::m_acSet2 db 'BCDORSJAMP5LEKTUYX3012QV67ZGF984',0 中取
奇数字符从 SystemState::m_acSet1 db 'NIWHSALRMPJ5EKTUYX3012QV67ZGF984',0 中取
注册码的第一个字符为0,偶数字符
再往下看

函数SystemState::ConvertNToHexa,将part_5转换为密钥(aes128),当成一个int64来看。
来看看函数SystemState::ConvertNToHexa的关键代码:

将part_5紧凑起来。因为两个字符级是32,index最大31,占5个bit,因此将这些5bit合并,使得每个字节的每个bit都利用。
同时将这个int64变成一个字符串。
jmp SystemState::GenerateNinHexa(uchar *,ulong long) ; 将int64变成字符串
再看看part_26的转换:

将26个index,也紧凑起来。
继续
调用CAESDecryptor::DecryptText,将part_26用part_5作密钥来解密

解密之后,回到函数SystemState::GetState
校验解出来的16个字节,以及part_5
解密出来的16个字节必须是 ds:__ZL13KeyForGeneric

part_5得到的int64,必须比上面提到的int64 0x00000000 001e8480 要小
Over。
剩下的活,就是写注册机。
该公司的另一款产品web2delight,算法一样。
关键代码为:
- (NSString*) doKeygen:(int)indexofproduct atusername:(NSString*)username atEmail:(NSString*)email
{
NSString *szkey;
unsigned char indata_web2delight[17] = {0x75,0x18,0x10,0x25,0x86,0x37,0x8B,0xDE,
0x19,0xA7,0x21,0x90,0xD3,0x12,0xB4,0x86,0x00};
unsigned char indata[17] = {0x86,0x97,0xB3,0xF1,0x6C,0xD2,0x22,0xE8,
0x9B,0xCE,0xA7,0xC6,0xAE,0x65,0xB1,0xBB,0x00};
unsigned char outdata[17] = {0};
unsigned char aeskeydata[17] = {0};
const char* set1 = "NIWHSALRMPJ5EKTUYX3012QV67ZGF984";
const char* set2 = "BCDORSJAMP5LEKTUYX3012QV67ZGF984";
const unsigned long long ullKeyLowLimit = 0x0;
const unsigned long long ullKeyHighLimit = 0x001E8480;//1,1D,1,4,0
const unsigned long long ullKeyLowLimitWeb2 = 0x0;
const unsigned long long ullKeyHighLimitWeb2 = 0x00004E20;//
unsigned long long ullKeyRandom = 0;
unsigned char key5[5] = {0};
unsigned char otherkey26[26] = {0};
unsigned char c = 0;
char szckey[33] = {0};
int i = 0;
unsigned char halfbyte = 0;
int j = 0;
srand(time(NULL));
if(indexofproduct == 0)
{
ullKeyRandom = rand() % (ullKeyHighLimit - ullKeyLowLimit) + ullKeyLowLimit;
}
else if(indexofproduct == 1)
{
ullKeyRandom = rand() % (ullKeyHighLimitWeb2 - ullKeyLowLimitWeb2) + ullKeyLowLimitWeb2;
}
else
{
return nil;
}
for(i = 0; i < 5;i++)
{
c = ullKeyRandom >> (i) * 5;
key5[i] = c & 0x1F;
}
c = rand() % (31 - 5); //the last char of registration code
for(i = 0; i < 16;i++)
{
halfbyte = Gethalfbytefromint64(ullKeyRandom,i);
aeskeydata[15 - i] = halfbyte2hexchar(halfbyte);
}
if(indexofproduct == 0)
{
aes_encrypt(indata,
outdata,
aeskeydata);
}
else if(indexofproduct == 1)
{
aes_encrypt(indata_web2delight,
outdata,
aeskeydata);
}
else
{
return nil;
}
//5 * 8 = 40, 40 / 5 = 8
otherkey26[0] = outdata[0] & 0x1F;
otherkey26[1] = ((outdata[1] & 0x3) << 3) | (outdata[0] >> 5);
otherkey26[2] = (outdata[1] >> 0x2) & 0x1F;
otherkey26[3] = ((outdata[2] & 0xF) << 1) | (outdata[1] >> 7);
otherkey26[4] = ((outdata[3] & 0x1) << 4) | (outdata[2] >> 4);
otherkey26[5] = (outdata[3] >> 1) & 0x1F;
otherkey26[6] = ((outdata[4] & 0x7) << 2) | (outdata[3] >> 6);
otherkey26[7] = (outdata[4] >> 3) & 0x1F;
otherkey26[8] = (outdata[5]) & 0x1F;
otherkey26[9] = ((outdata[6] & 0x3) << 3) | (outdata[5] >> 5);
otherkey26[10] = (outdata[6] >> 2) & 0x1F;
otherkey26[11] = ((outdata[7] & 0xF) << 1) | (outdata[6] >> 7);
otherkey26[12] = ((outdata[8] & 0x1) << 4) | (outdata[7] >> 4);
otherkey26[13] = (outdata[8] >> 1) & 0x1F;
otherkey26[14] = ((outdata[9] & 0x7) << 2) | (outdata[8] >> 6);
otherkey26[15] = (outdata[9] >> 3) & 0x1F;
otherkey26[16] = (outdata[10]) & 0x1F;
otherkey26[17] = ((outdata[11] & 0x3) << 3) | (outdata[10] >> 5);
otherkey26[18] = (outdata[11] >> 2) & 0x1F;
otherkey26[19] = ((outdata[12] & 0xF) << 1) | (outdata[11] >> 7);
otherkey26[20] = ((outdata[13] & 0x1) << 4) | (outdata[12] >> 4);
otherkey26[21] = (outdata[13] >> 1) & 0x1F;
otherkey26[22] = ((outdata[14] & 0x7) << 2) | (outdata[13] >> 6);
otherkey26[23] = (outdata[14] >> 3) & 0x1F;
otherkey26[24] = (outdata[15]) & 0x1F;
otherkey26[25] = ((outdata[16] & 0x3) << 3) | (outdata[15] >> 5);
for(i = 0; i < c;i++)
{
szckey[i] = otherkey26[i];
j = szckey[i];
if((i % 2) == 0)
{
szckey[i] = set2[j];
}
else
{
szckey[i] = set1[j];
}
}
for(i = c; i < c + 5;i++)
{
szckey[i] = key5[i - c];
j = szckey[i];
if(((i - c) % 2) == 0)
{
szckey[i] = set2[j];
}
else
{
szckey[i] = set1[j];
}
}
for(i = c + 5; i < 31;i++)
{
szckey[i] = otherkey26[i - 5];
j = szckey[i];
if(((i - 5) % 2) == 0)
{
szckey[i] = set2[j];
}
else
{
szckey[i] = set1[j];
}
}
szckey[31] = set1[c];
NSLog(@" key is %s",szckey);
szkey = [[NSString stringWithCString:(const char*)szckey] retain];
return szkey;
}
ObjC使用msgSend来调用函数。
比如:调用-_VLRegister_validateKeyWithInfo_Fortype__的地方

Function_name_ptr保存在[esp+4]中


查看交叉参考,__inst_meth:0019417Co,来到:
然后才看到函数地址
我写了个Python脚本,用IDAPython来跑,可以添加注释,显示出函数名,并添加交叉参考。速度比较慢。跑完Voila,要用18分钟。脚本运行后,鼠标最好就不动了。否则IDA会假死。
Python 脚本为:
#
# Mac OS Objective-c msgSend function Helper
#
# winndy CNwinndy@hotmail.com
#
#
#
from idaapi import *
from idautils import *
from idc import *
def GetSegmentof__imp__objc_msgSend():
print "get address of __imp__objc_msgSend !"
segm_num = get_segm_qty()
segm_name = ''
segm_class = ''
for segmindex in range(segm_num):
segm = getnseg(segmindex)
seg_name = get_segm_name(segm.startEA)
seg_truename = get_true_segm_name(segm)
seg_class = get_segm_class(segm)
seg_type = segtype(segm.startEA)
print ' [-] segmentation %d Name: %s / Type: %d / True Name: %s / class %s' % (segmindex, seg_name, seg_type, seg_truename, seg_class)
if SEG_XTRN == seg_type:
print 'found segment %d' %(segmindex)
return segm
def Getaddressof_objc_msgSend():
func_num = get_func_qty()
for funcindex in range(func_num):
func = getn_func(funcindex)
func_name = get_func_name(func.startEA)
print "function %d : %s" %(funcindex, func_name)
if '_objc_msgSend' == func_name:
return func
#__text:000A9CBA A1 CC 00 18 00 mov eax, ds:off_1800CC
# mov eax, dword ptr[1800CC]
def is_mov_mem(inst,reg):
return ((inst.itype == idaapi.NN_mov) and
(idaapi.get_instruction_operand(inst,0).type == idaapi.o_reg) and
(idaapi.get_instruction_operand(inst,0).reg == reg) and
(idaapi.get_instruction_operand(inst,1).type == idaapi.o_mem))
#__text:000A9CBF 89 44 24 04 mov [esp+18h+var_14], eax
def is_mov_esp_4(inst):
return ((inst.itype == idaapi.NN_mov) and
(idaapi.get_instruction_operand(inst,0).type == idaapi.o_displ) and
(idaapi.get_instruction_operand(inst,0).reg == 4) and
(idaapi.get_instruction_operand(inst,0).addr == 4) and
(idaapi.get_instruction_operand(inst,1).type == idaapi.o_reg))
#__text:000A9CE8 89 45 0C mov [ebp+arg_4], eax
def is_mov_ebp_C(inst):
return ((inst.itype == idaapi.NN_mov) and
(idaapi.get_instruction_operand(inst,0).type == idaapi.o_displ) and
(idaapi.get_instruction_operand(inst,0).reg == 5) and
(idaapi.get_instruction_operand(inst,0).addr == 0x0C) and
(idaapi.get_instruction_operand(inst,1).type == idaapi.o_reg))
# 8B1C24 mov ebx, [esp+0]; retn
def is_mov(inst):
return ((inst.itype == idaapi.NN_mov) and
(idaapi.get_instruction_operand(inst,0).type == idaapi.o_reg) and
(idaapi.get_instruction_operand(inst,1).type == idaapi.o_displ))
def is_pop(inst):
return ((inst.itype == idaapi.NN_pop) and
(idaapi.get_instruction_operand(inst,0).type == idaapi.o_reg) and
(idaapi.get_instruction_operand(inst,1).type == idaapi.o_void))
#__text:001397EA 8B 83 36 92 04 00 mov eax, [ebx+49236h]
def is_mov2(inst, reg):
print 'is_mov2',(inst.itype == idaapi.NN_mov),(idaapi.get_instruction_operand(inst,0).type == idaapi.o_reg), \
(idaapi.get_instruction_operand(inst,1).reg == reg), (idaapi.get_instruction_operand(inst,1).type == idaapi.o_displ)
return ((inst.itype == idaapi.NN_mov) and
(idaapi.get_instruction_operand(inst,0).type == idaapi.o_reg) and
(idaapi.get_instruction_operand(inst,1).reg == reg) and
(idaapi.get_instruction_operand(inst,1).type == idaapi.o_displ))
def is_lea(inst, reg):
return ((inst.itype == idaapi.NN_lea) and
(idaapi.get_instruction_operand(inst,1).reg == reg) and
(idaapi.get_instruction_operand(inst,1).type == idaapi.o_displ))
"""
#from ihood.py,by Cameron Hotchkies,
def find_anchor(address):
func_start = GetFunctionAttr(address, FUNCATTR_START)
func_end = GetFunctionAttr(address, FUNCATTR_END)
cursor = func_start
while cursor < func_end:
# call $+5; pop ebx
if (Byte(cursor) == 0xE8 and Dword(cursor+1) == 0x00000000 and Byte(cursor+5)==0x5B):
return cursor+5
elif GetMnem(cursor) == "call":
subfunc = Rfirst0(cursor)
# mov ebx, [esp+0]; retn
if (Byte(subfunc) == 0x8B and Byte(subfunc+1) == 0x1C and Byte(subfunc+2) == 0x24 and Byte(subfunc+3) == 0xC3):
return NextNotTail(cursor)
else:
cursor = NextNotTail(cursor)
else:
cursor = NextNotTail(cursor)
return BADADDR
"""
def find_anchor2(ea):
# call $+5; pop ebx
pattern = 'E8 00 00 00 00'
print '%08lx find_anchor2' %(ea)
func = get_func(ea)
if (func is None):
print 'cannot get func from address %08lx' %(ea)
return -1,BADADDR,-1;
ea1 = find_binary(func.startEA, func.endEA,pattern,16,SEARCH_DOWN)
print 'found %08lx between %08lx and %08lx' %(ea1,func.startEA, func.endEA)
if (ea1 != BADADDR) and (ea1 > func.startEA) and (ea1 < func.endEA):
ea2 = ea1 + 5
#get reg
idaapi.ua_ana0(ea2)
inst = idaapi.get_current_instruction()
if(not is_pop(inst)):
return -1,BADADDR,-1;
reg = idaapi.get_instruction_operand(inst,0).reg;
return 0,ea2,reg
cursor = func.startEA
while cursor < func.endEA:
if GetMnem(cursor) == "call":
subfunc = Rfirst0(cursor)
# 8B0424 mov eax, dword ptr [esp]
# 8B0C24 mov ecx, dword ptr [esp]
# 8B1424 mov edx, dword ptr [esp]
# 8B1C24 mov ebx, [esp+0]; retn
#if(not is_mov(inst)):
#if (Byte(subfunc) == 0x8B and """Byte(subfunc+1) == 0x1C and""" Byte(subfunc+2) == 0x24 and Byte(subfunc+3) == 0xC3):
if (Byte(subfunc) == 0x8B and Byte(subfunc+2) == 0x24 and Byte(subfunc+3) == 0xC3):
#get reg
idaapi.ua_ana0(subfunc)
inst = idaapi.get_current_instruction()
reg = idaapi.get_instruction_operand(inst,0).reg;
return 1,NextNotTail(cursor),reg
else:
cursor = NextNotTail(cursor)
else:
cursor = NextNotTail(cursor)
#no anchor,mov eax,offset funcname_ptr
return 2,BADADDR,-1
def HandleOneRefCall(ea):
#__text:000A9CBA A1 CC 00 18 00 mov eax, ds:off_1800CC
#__text:000A9CBF 89 44 24 04 mov [esp+18h+var_14], eax
#__text:000A9CC3 89 34 24 mov [esp+18h+var_18], esi
#__text:000A9CC6 E8 AB 26 10 00 call _objc_msgSend
#__text:000A9CE8 89 45 0C mov [ebp+arg_4], eax
#__text:000A9CEB 89 55 08 mov [ebp+arg_0], edx
#__text:000A9CEE 83 C4 10 add esp, 10h
#__text:000A9CF1 5B pop ebx
#__text:000A9CF2 5E pop esi
#__text:000A9CF3 C9 leave
#__text:000A9CF4 E9 7D 26 10 00 jmp _objc_msgSend
#(inst.itype == idaapi.NN_call)
#print 'in HandleOneRefCall'
#ea1 = prevaddr(ea)
ea1 = prev_not_tail(ea)
func = get_func(ea)
while ea1 >= func.startEA:
#get reg
idaapi.ua_ana0(ea1)
inst = idaapi.get_current_instruction()
if(is_mov_esp_4(inst)):
reg = idaapi.get_instruction_operand(inst,1).reg;
ea2 = prev_not_tail(ea1)
while ea2 >= func.startEA:
#get reg
idaapi.ua_ana0(ea2)
inst = idaapi.get_current_instruction()
if(is_mov_mem(inst,reg)):
#find it
Addcmtxref(ea2,get_instruction_operand(inst,1).addr)
return 1
else:
ea2 = prev_not_tail(ea2)
break
else:
ea1 = prev_not_tail(ea1)
print '%08lx not done' %(ea)
return 0
def HandleOneRefJmp(ea):
#__text:000A9CBA A1 CC 00 18 00 mov eax, ds:off_1800CC
#__text:000A9CBF 89 44 24 04 mov [esp+18h+var_14], eax
#__text:000A9CC3 89 34 24 mov [esp+18h+var_18], esi
#__text:000A9CC6 E8 AB 26 10 00 call _objc_msgSend
#__text:000A9CE3 A1 78 12 18 00 mov eax, ds:runModalForWindow__PTR
#__text:000A9CE8 89 45 0C mov [ebp+arg_4], eax
#__text:000A9CEB 89 55 08 mov [ebp+arg_0], edx
#__text:000A9CEE 83 C4 10 add esp, 10h
#__text:000A9CF1 5B pop ebx
#__text:000A9CF2 5E pop esi
#__text:000A9CF3 C9 leave
#__text:000A9CF4 E9 7D 26 10 00 jmp _objc_msgSend
#(inst.itype == idaapi.NN_jmp)
#print 'in HandleOneRefJmp'
#ea1 = prevaddr(ea)
ea1 = prev_not_tail(ea)
func = get_func(ea)
while ea1 >= func.startEA:
#get reg
idaapi.ua_ana0(ea1)
inst = idaapi.get_current_instruction()
if(is_mov_ebp_C(inst)):
reg = idaapi.get_instruction_operand(inst,1).reg;
ea2 = prev_not_tail(ea1)
while ea2 >= func.startEA:
#get reg
idaapi.ua_ana0(ea2)
inst = idaapi.get_current_instruction()
if(is_mov_mem(inst,reg)):
#find it
Addcmtxref(ea2,get_instruction_operand(inst,1).addr)
return 1
else:
ea2 = prev_not_tail(ea2)
break
else:
ea1 = prev_not_tail(ea1)
print '%08lx not done' %(ea)
return 0
def HandleOneRef(ea):
#__text:000A9CBA A1 CC 00 18 00 mov eax, ds:off_1800CC
#__text:000A9CBF 89 44 24 04 mov [esp+18h+var_14], eax
#__text:000A9CC3 89 34 24 mov [esp+18h+var_18], esi
#__text:000A9CC6 E8 AB 26 10 00 call _objc_msgSend
#__text:000A9CE8 89 45 0C mov [ebp+arg_4], eax
#__text:000A9CEB 89 55 08 mov [ebp+arg_0], edx
#__text:000A9CEE 83 C4 10 add esp, 10h
#__text:000A9CF1 5B pop ebx
#__text:000A9CF2 5E pop esi
#__text:000A9CF3 C9 leave
#__text:000A9CF4 E9 7D 26 10 00 jmp _objc_msgSend
print '%08lx in HandleOneRef' %(ea)
idaapi.ua_ana0(ea)
inst = idaapi.get_current_instruction()
if(inst.itype == idaapi.NN_call):
ret = HandleOneRefCall(ea)
elif(inst.itype == idaapi.NN_jmp):
ret = HandleOneRefJmp(ea)
else:
print 'error'
def isValidAddress(ea):
if(idaapi.cvar.inf.minEA <= ea and ea < idaapi.cvar.inf.maxEA):
return True
else:
return False;
def GetFunctionAddressFromNameoff(nameoffset):
print "in GetFunctionAddressFromNameoff()"
refListOfname = DataRefsTo(nameoffset)
ref_count = len(refListOfname)
print "total ref count of nameoffset %08lx is %08X(%d)" %(nameoffset,ref_count, ref_count)
funcaddresslist = []
for i in range(ref_count):
segmname = get_segm_name(refListOfname[i])
if '__inst_meth' != segmname:
continue
else:
a = (refListOfname[i] + 8)
funcaddress = get_long(a)
funcaddresslist.append(funcaddress)
return funcaddresslist
def GetLenOfAscii(ea):
length = 0
b = get_byte(ea)
while b != 0 :
length = length + 1
ea = ea + 1
b = get_byte(ea)
if(length > 255):
break
return length + 1
def Addcmtxref(ea_to_addcmt,ea_name_ptr):
comment = '%08lx' % (ea_name_ptr)
set_cmt(ea_to_addcmt, comment, False)
OffsetToFunctionName = get_long(ea_name_ptr)
if(isValidAddress(OffsetToFunctionName)):
# Convert that to string
flags = get_flags_novalue(OffsetToFunctionName)
if(not isHead(flags)):
print 'ea_to_addcmt = %08lx,ea_name_ptr = %08lx,failed' %(ea_to_addcmt,ea_name_ptr)
return
length = GetLenOfAscii(OffsetToFunctionName)
do_unknown_range(OffsetToFunctionName,length,DOUNK_EXPAND or DOUNK_DELNAMES)
#MakeStr(OffsetToFunctionName,BADADDR) #failed to make ascii string
make_ascii_string(OffsetToFunctionName,length,ASCSTR_C)
flags = get_flags_novalue(ea_name_ptr)
if(not has_name(flags)):
name1 = get_ascii_contents(OffsetToFunctionName,get_max_ascii_length(OffsetToFunctionName,ASCSTR_C),ASCSTR_C)
if(name1 is None):
name1 = get_name(BADADDR,ea_name_ptr)
name1 = name1 + '_PTR'
if(MakeName(ea_name_ptr,name1) == 0):
# We cannot create the string, create alternate string
make_name_auto(ea_name_ptr)
#make_name_public(ea_name_ptr)
comment += ' %s' %(name1)
set_cmt(ea_to_addcmt, comment, False)
print '%08lx : %s' %(ea_to_addcmt, comment)
else :
#print "isASCII return true"
name1 = get_name(BADADDR,ea_name_ptr)
comment += ' %s' %(name1)
set_cmt(ea_to_addcmt, comment, False)
print '%08lx : %s' %(ea_to_addcmt, comment)
func2list = GetFunctionAddressFromNameoff(OffsetToFunctionName)
if 0 != len(func2list):
for func2 in func2list:
comment += '\n%08lx %s' %(func2, get_func_name(func2))
add_cref(ea_to_addcmt,func2,fl_CN | XREF_USER)
set_cmt(ea_to_addcmt, comment, False)
print '%08lx : %s' %(ea_to_addcmt, comment)
else:
flags = get_flags_novalue(ea_name_ptr)
if(not isHead(flags) or not isData(flags)):
comment += ' %08lx' %(ea_name_ptr)
set_cmt(ea_to_addcmt, comment, False)
print '%08lx : %s' %(ea_to_addcmt, comment)
return
length = GetLenOfAscii(ea_name_ptr)
do_unknown_range(ea_name_ptr,length,DOUNK_EXPAND or DOUNK_DELNAMES)
make_ascii_string(ea_name_ptr,length,ASCSTR_C)
name1 = get_ascii_contents(ea_name_ptr,get_max_ascii_length(ea_name_ptr,ASCSTR_C),ASCSTR_C)
comment += ' \"%s\"' %(name1)
set_cmt(ea_to_addcmt, comment, False)
print '%08lx : %s' %(ea_to_addcmt, comment)
def HandleOneRefFunction(ea):
#__text:00002CF5 E8 00 00 00 00 call $+5
#__text:00002CFA 5B pop ebx
pattern = 'E8 00 00 00 00'
pattern_lea = ''
mask = r'\0\0\0\0\0'
func = get_func(ea)
#ea1 = bin_search(func.startEA, func.endEA,pattern,None,len(pattern),BIN_SEARCH_FORWARD,BIN_SEARCH_NOCASE)
#print '%08lx : address of call $+5' %(ea1)
ea1 = find_binary(func.startEA, func.endEA,pattern,16,SEARCH_DOWN)
print '%08lx : address of call $+5' %(ea1)
ea2 = ea1 + 5
#get reg
idaapi.ua_ana0(ea2)
inst = idaapi.get_current_instruction()
if(not is_pop(inst)):
return;
reg = idaapi.get_instruction_operand(inst,0).reg;
#8D 10^^^*** ? ? 00 00
#^^^:reg1
#***:reg2
#pattern_lea = '8D 8%1d ? ? 00 00' %(reg)
pattern_lea = '8D ? ? ? ? 00'
#print pattern_lea
#__text:00002B49 8D 83 EB 24 00 00 lea eax, [ebx+24EBh]
ea3 = find_binary(ea2, func.endEA,pattern_lea,16,SEARCH_DOWN)
#__text:0013AE9B 8B 83 0C 81 04 00 mov eax, [ebx+4810Ch]
while (BADADDR != ea3) and (ea3 < func.endEA) and(ea3 > func.startEA):
flags = getFlags(ea3)
if(not isHead(flags)):
ea3 = find_binary(ea3 + 1, func.endEA,pattern_lea,16,SEARCH_DOWN)
continue
idaapi.ua_ana0(ea3)
inst = idaapi.get_current_instruction()
if(not is_lea(inst, reg)):
ea3 = find_binary(ea3 + 6, func.endEA,pattern_lea,16,SEARCH_DOWN)
continue
#print '%08lx : address of lea eax, [ebx+????????h]' %(ea3)
delta = get_long(ea3 + 2)
Addcmtxref(ea3,ea2 + delta)
instsize = get_item_size(ea3)
#print instsize
ea3 = ea3 + instsize
ea3 = find_binary(ea3, func.endEA,pattern_lea,16,SEARCH_DOWN or SEARCH_NEXT)
#print ea3
pattern_mov = '8B ? ? ? ? 00'
#__text:0013AE9B 8B 83 0C 81 04 00 mov eax, [ebx+4810Ch]
ea3 = find_binary(ea2, func.endEA,pattern_mov,16,SEARCH_DOWN)
#__text:000D6091 8B 35 DC F0 17 00 mov esi, ds:off_17F0DC
#__text:000D6097 89 74 24 04 mov [esp+38h+var_34], esi
#__text:000D609B 89 04 24 mov [esp+38h+var_38], eax
#__text:000D609E E8 D8 62 0D 00 call _objc_msgSendSupe
while (BADADDR != ea3) and (ea3 < func.endEA) and(ea3 > func.startEA):
flags = getFlags(ea3)
if(not isHead(flags)):
ea3 = find_binary(ea3 + 1, func.endEA,pattern_mov,16,SEARCH_DOWN or SEARCH_NEXT)
continue
idaapi.ua_ana0(ea3)
inst = idaapi.get_current_instruction()
print '%08lx : address of mov eax, [ebx+????????h]' %(ea3)
if(not is_mov2(inst, reg)):
ea3 = ea3 + 6
ea4 = ea3
print '%08lx : next address1' %(ea3)
ea3 = find_binary(ea4, func.endEA,pattern_mov,16,SEARCH_DOWN or SEARCH_NEXT)
if(ea3 <= ea4):
print 'error.%08lx is found within %08lx and %08lx' %(ea3, ea4,fuc.endEA)
raw_input('111')
return
print '%08lx : next address2' %(ea3)
continue
#print '%08lx : address of mov eax, [ebx+????????h]' %(ea3)
delta = get_long(ea3 + 2)
Addcmtxref(ea3,ea2 + delta)
instsize = get_item_size(ea3)
ea3 = ea3 + instsize
ea3 = find_binary(ea3, func.endEA,pattern_mov,16,SEARCH_DOWN or SEARCH_NEXT)
def BelongToFunction(start,end,EA):
return EA >= start and \
EA < end
def start():
GetSegmentof__imp__objc_msgSend()
segm = GetSegmentof__imp__objc_msgSend()
nextEA = nextaddr(segm.startEA);
print get_item_size(segm.startEA)
print ItemSize(segm.startEA)
ea = segm.startEA;
while segm.endEA > ea :
print '%s' %(LineA(ea,1))
if (ua_ana0(ea) > 0):
instsize = idaapi.cvar.cmd.size
print '%08x : %s \nInstruction size: %d bytes' %(ea, GetDisasm(ea),instsize)
else:
print 'Not at an instruction.'
if has_name(ea):
print '%s' %(get_name(BADADDR,ea))
if('__imp__objc_msgSend' == get_name(BADADDR,ea)):
refList1 = CodeRefsTo(ea, 1)
ref_count1 = len(refList1)
print "total ref count of __imp__objc_msgSend is %08X(%d)" %(ref_count1, ref_count1)
refList1.sort()
for i in range(ref_count1):
print '%08x : ref %08x(%d)' %(refList1[i],i,i)
func_objc_msgSend = get_func(refList1[i])
refList = CodeRefsTo(func_objc_msgSend.startEA, 1)
refList.sort()
ref_count = len(refList)
print "total ref count of _objc_msgSend is %08X(%d)" %(ref_count, ref_count)
func_contain_call_msgSend_list2 = []
for refaddress in refList:
func = get_func(refaddress)
if(func is None):
print "failed to process ref %08lx" %(refaddress)
continue
print '\nfrom %08lx found function %08lx %08lx' %(refaddress,func.startEA,func.endEA)
retcode,ebx,reg = find_anchor2(refaddress)
print '%08lx return %d %08lx %d' %(refaddress,retcode,ebx,reg)
#break
if (retcode == -1):
print 'internal error while handle %08lx' %(refaddress)
elif (retcode in [0,1]):
#else if((retcode == 0) or (retcode == 1)):
# hanle one function by one
#for all functions that contain call msgSend
belong = False
for (start,end) in func_contain_call_msgSend_list2:
if(BelongToFunction(start,end,refaddress)):
belong = True
break;
if(belong):
print '%08lx is already been hadled in HandleOneRefFunction()' %(refaddress)
continue;
func_contain_call_msgSend = get_func(refaddress)
HandleOneRefFunction(func_contain_call_msgSend.startEA)
if(not ((func_contain_call_msgSend.startEA,func_contain_call_msgSend.endEA) in func_contain_call_msgSend_list2)):
func_contain_call_msgSend_list2.append((func_contain_call_msgSend.startEA, \
func_contain_call_msgSend.endEA))
elif(retcode == 2):
# hanle one reference by one
HandleOneRef(refaddress)
else:
print 'error'
ea = ea + 4
start()