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()