作者:www.datarescue.com

                                                              mailto:winroot@126.com

2004-11-20    初步翻译完成,希望大家指正错误,谢谢!

我的鸟语太差大概翻译了一下,大家凑合着能看懂就行了:-)有些地方用自己理解的意思改写了一下!

本文的主要内容就是讲如何用IDA来辅助识别各种类型的数据.

版权信息:所有版权归原文作者所有,如许转载清保持文章完整性。

索引

1  第一节:C语言的小程序
2  第二节:基本类型的识别
3  第三节:操作数格式
4  第四节:字符和字符串的操作
5  第五节:数组
6  第六节:枚举类型
7  第七节:Bit-fields(位域)
8  第八节:结构体
9  第九节:结构变量和结构数组
10 第十节:联合体和结构体中的结构体
11 第十一节:可变的结构体
12 第十二节:结构体偏移
13 第十三节:联合体偏移量
14 第十四节:地址偏移量
15 第十五节:最终逆向结果


附录

 

第一节:C语言的小程序

为了演示IDA的功能先写一段小程序。(代码在附录)程序在此 源代码

程序执行结果:

CUSTOMERS:
CUSTOMER 0001: Peter (m)
CUSTOMER 0002: John (m)
CUSTOMER 0003: Mary (f)

PRODUCTS:
PRODUCT 0001: BOOK: IDA QuickStart Guide
PRODUCT 0002: SOFTWARE: IDA Pro: PC; WINDOWS DOS; DISASSEMBLY
PRODUCT 0003: SOFTWARE: PhotoRescue: PC MAC; WINDOWS OS-X; RECOVERY
PRODUCT 0004: SOFTWARE: aCrypt: PC; WINDOWS; CRYPTOGRAPHY

                                                               TOP

----------------------------------------------------------------------

第二节:基本类型的识别

用IDA分析我们前面的程序,我们会发现下图的类型

只要按"D"我们就可以任意转换这些不确定的类型.可以变成byte,word,dword(db,dw,dd)。

当然你也可以设置更多的数据转换类型:

选择“Options”菜单的“Setup data types”命令就可以设置了

值得注意的是:你在数据转换的时候,它是依据数据自身的结构来转换的。我们按“D”的时候,

如果下一个字节已经被你转换过,你的本次转换,IDA将会提示让你确认。

注:如果你想改变这种默认设置可以在“Options”菜单“Convert already defined bytes”命令里设置

撤销你的所有转换按“U”键。

                                                            TOP

-------------------------------------------------------------------------------------

第三节:操作数格式

数据类型自定义转换后,被操作过的数据(就是你按过“D”的)的进制IDA也是可以自定义转变的,

通过在“Operands”工具栏的“Number”命令我们可以随意转换数字的进制

最下面的“Toggle leading point”就是填补数据前的空位为0(就是说如果当前数据未占满数据格式的所有位高位用0来填补)

 

 

IDA还可以转换数据的标志位(就是正负)具体操作如下图:

 

最后呢~~如果这些转换你还不满意(够BT)当然你还可以自定义数据进制如图:

                                                                TOP

-----------------------------------------------------------------------------------------

第四节:字符和字符串的操作

 

作者又说话了:很多程序都是包含字符串的,一些被操作过的数据(就是你按过“D”的)可以转化为

字符,使用的命令就在“Operands”工具栏上

 

由于编程语言的不同造成字符串也有不同的格式,当然IDA就支持所有的格式了。

IDA在转化后会在地址添加一个名字。因为我们的程序是c的所以就找到c的字符串。具体操作如图:

如果不是C写的程序怎么办呢?我们可以在“Options”菜单“ASCII string style”命令中设置。

允许你修改其它类型为默认设置,使用默认设置的快捷键是“A”,或者自定义一种类型可以使用不常用的终止字符。

                                                                    TOP

--------------------------------------------------------------------------

第五节:数组

在c中,ASCII字符串被认为是字符数组,IDA是如何处理数组的呢?
我们用最常用命令来定义数组中的第一个元素,设置第一个元素类型为byte,格式为char,然后点击“*”号键(或者“Edition ”工具栏的“Array”命令)来创建数组。这时弹出一个对话框,可以设置很多变量。

你可以定义数组一行的显示个数,还可以使用“Element width”来设置他们之间的宽度。
使用“Use dup construct ”选项可以合并连贯的相似字节,“ Display index ”选项可以像注释一样显示数组的下标。

例如我们设置一个有64个元素的数组,一行有8个元素,每个元素之间的宽度为4,不选取“dup constructs”,选取“Display index ”,我们就可以得到下面的数组。

当IDA遇到未被识别的字节他会用红色的高亮显示。


当然你也可以选择一个范围来创建数组,IDA会自适应的设定。

                                                                            TOP

------------------------------------------------------------------------------------

第六节:枚举类型

还记得我们在C程序中定义的product_category_t 类型吗?
让我们用IDA的“Enumerations”来定义一下。

首先,我们打开“Enumerations”窗口来创建一个新的枚举类型

 

我们输入我们的枚举类型值

 

在check_product()函数,我们可以用枚举类型重新定义一些操作数。
右键点击在数值上,就会弹出一个菜单,选择“Symbolic constant”。
IDA就会自动列举枚举值,用以匹配当前的数值。

 

操作完成,我们就会得到下面的结果:

                                                                                                TOP

-----------------------------------------------------------------------------------------------------

第七节:Bit-fields(位域)

BTW:Bit-fields,我的理解就是在结构体中的位标志。太菜!希望高手指正!

现在,我们来定义一下在software_info_t 结构中的bitfields。
IDA的观点就是,bitefields是一种特殊的枚举类型。
我们可以选择在枚举类型创造窗口中的“Bitfield”选项。

还记得我们曾经在我们的程序中建立了两种不同类型的bitfields ,
plateform和os包含了一种隐藏的模式:用来包含组合模式(用逻辑或来操作) 。因为一种产品可以同时在几种plateforms和OS的组合。另一方面,category bitfield 中每一个数字表示一种类别:一种产品每次只能属于一种类别。
在IDA中一种指定的模式,bitfield只能包含一个值。所以在描述plateform 和category bitfields时为了显示组合模式,我们必须创建一个小的bitfields,每个值的一个bit.

现在我们开始创建category bitfield。mask值为0x3 (2 bits).我们指定一个名字、一个值、还有bitfield mask。我们还需要定义mask的名字:这个我们不用IDA自动生成的,IDA有一个内存助手可以帮助生成。

当所有的bitfields被输入,我们就会得到下面的结果:

用Operands 工具栏上的Enum member命令就可以定义我们程序中的Enum member数据

                                                                                                    TOP

---------------------------------------------------------------------------------------------------------

第八节:结构体

我们的程序当中包含了很多结构体。现在让我们来在IDA中描述一下结构体,
看看是怎么提高汇编代码的可读性。
第一步,我们必须打开Structures 窗口,来创建一个新的结构体类型。

结构体的成员是一汇编的模式定义的。让我们来定义software_t 结构中的第一个成员。
一直按“D”知道它变成“dd”意思就是这个成员的值为 dword类型。
把它的格式定义为我们以前定义好的software_info_t 枚举类型,然后我们用Rename命令输入一个适当的名字:info

开始定义第二个成员,这次使用ASCII命令(按“A”),在这个环节
IDA会弹出一个专用对话框用来设定字符串的大小

我们还可以从已经分析好的数据中来建立结构体。
举个例子:假设我们选择了一块数据正好是和我们的customer_t结构体的数据格式一样,我们就可以用IDA的“Create struct from data ”命令来创建结构体

 

一旦使用了这个命令,IDA就会在Structures窗口创建一个相对应的结构体
我们使用“A”键来修改name成员的长度为32bytes(和我们源代码中定义的一样),然后再给结构体一个好听的名字。



我们拿这些结构体有什么用呢?IDA提供给我们两种方法:
·Apply structure types to initialized data in the program. 
·Convert operands as offsets inside structures.
我们将在下面的教程当中来介绍这两种方法

                                                                                            TOP

---------------------------------------------------------------------------------------------------------------------

第九节:结构变量和结构数组

现在让我们用来customer_t结构体整理另外一个客户信息John。
把鼠标指针放在我们定义的结构体的第一个自己上面,然后使用Struct var命令。

这样我们就得到了一个新的结构体变量。IDA会自动在结构体成员的后面加上变量名的。

 

通过我们的源码,我们知道有一个包含个4元素的customers数组,我们先前把
Peter和John都定义为 customer_t 结构体了。现在取消对Join结构变量的定义,然后在Peter结构上按“*”键创建我们的customer数组,这样IDA就弹出一个数组设置框他会自动检测出来我们要创建的数组最大数是4。

下来我们就看到创建好的数组了,剩下的就是改一下数组的名字。

                                                                                                TOP

-------------------------------------------------------------------------------------------------------

第十节:联合体和结构体中的结构体

IDA中可以像定义标准结构体那样来定义联合体。
让我们来试着定义product_u 这个联合体吧。
book_t和software_t这两个结构体我们已经定义过了。
IDA认为联合体就是一种特别的结构体:因此我们打开Structures窗口,运行Add struct type命令,在对话框中我们选择创建Create union 选项。

我们可以使用IDA常用的命令来创建联合体成员,分别添加一个book_t 结构体类型的book和一个software_t 结构体的software联合体成员

当然结构体也可以嵌套一个结构体。事实上,我们刚才做的例子就实现了。
记住IDA认为联合体只不过是一种特殊的结构体

                                                                                        TOP

----------------------------------------------------------------------------------------------

第十一节:可变的结构体

我们还记得有一个softwares_t 结构体。结构体softs 的长度是不确定的。
在汇编中,我们必须创建一个大小可变的结构体~。这种结构体创建的时候和普通的一样,仅仅最后一个元素定义的数组元素个数为0。

 

既然IDA不能计算出这种结构体的大小,我们就必须通过选择结构体的区域,来定义大小。

我们可以看到所有的类型IDA用注释模式来显示成员名称

                                                                                            TOP

----------------------------------------------------------------------------------------------------

第十二节:结构体偏移

现在我们知道如何定义联合体和结构体了。现在我们来将一些操作数指向他们原本指向的结构体。


在print_customer() 函数中,我们知道他只有一个指向customer_t结构体的参数。EAX寄存器初始化这个指针的值,使他指向customer_t 结构体。因此我们推断所有的[EAX+....]都是指向customer_t结构体成员的偏移。 

我们开始重新定义这些结构体变量的偏移,你右击在他们上面IDA会自动给你提供偏移的信息。

当我们把所有的偏移量都整理一下的话,汇编代码马上就变得清晰易懂了。

print_software()函数呢就是另外一个例子:EBX在初始化的时候指向了software_t 及构体。注意EBX寄存器在整个函数中都有应用(一个一个替换会累死的)。不要紧张,IDA会使用一次操作就能替换全部。
做法如下:
选择整个函数的代码,然后选在Operands工具栏上的Offset (struct) 命令。

弹出Structure offsets窗口。然我们在列表中选择EBX寄存器。
左边树形视图显示了在IDA中定义的所有结构。
右边就显示与EBX有关系的所有操作。如果我们选择了左边的一个结构,
IDA就会自动改变被选择代码中与结构体有关的偏移量。
树视图前面不同的符号表示经过计算后的状态。对号就表示完全匹配,相反就是不完全匹配。在我们的操作中正好完全匹配。

确定以后,我们就得到了下面的结果:

                                                                                                      TOP

--------------------------------------------------------------------------------------------------------------

第十三节:联合体偏移量

依靠产品种类,我们可以调用适当的函数来打印产品信息。
但是这一次的结构体偏移量跟以前不一样了,它是product_u联合体中的一个成员,它是一个数,这时我们就选择Edit struct 菜单中Select union member命令来处理

结果就是这样:

Structure offset对话框显示如何表明一个联合体成员。在你选择的区域中打开了这个窗口,IDA就会用“?”来显示联合体类型。


如果展开树视图中适当的分支,我们可以选择被描述为联合体成员的偏移量。
一旦选中,IDA会用在一种绿色的符号来表示偏移量指向的记录中的联合体。

                                                                                        TOP

--------------------------------------------------------------------------------------------------------

第十四节:地址偏移量

IDA也可以重新定义操作数。在下面的例子中,桔黄色的部分显示一个可能存在的参考~


使用Operands 工具栏上的Offset 按钮就可以进行转换。

                                                                                            TOP


--------------------------------------------------------------------------------------------------------------------

第十五节:最终逆向结果

To end this tutorial, we propose you a visual comparison of the original C source code and our final interactively disassembled code.

来look look我们用IDA整理的结果把

 
struct customer_t {
  long id;
  char name[32];
  char sex;
}

 
; -------------------------------------------------------------
customer_t struc ; (sizeof=0x28)
id dd ?
name db 32 dup(?)   ; string(C)
sex dd ?            ; char
customer_t ends
 
 
struct softwares_t {
  long count;
  software_t softs[];
};

 
; -------------------------------------------------------------
softwares_t struc ; (sizeof=0x4, variable size)
count dd ?
softs software_t 0 dup(?)
softwares_t ends
 
 
struct book_t {
  char title[128];
};
 
; -------------------------------------------------------------
book_t struc ; (sizeof=0x80)
title db 128 dup(?) ; string(C)
book_t ends
 
 
struct software_t {
  software_info_t info;
  char name[32];
};


; -------------------------------------------------------------
software_t struc ; (sizeof=0x24)
info dd ?           ; enum software_info_t
name db 32 dup(?)   ; string(C)
software_t ends
 
 
union product_u {
  book_t     book;
  software_t software;
};


; -------------------------------------------------------------
product_u union ; (sizeof=0x80)
book book_t ?
software software_t ?
product_u ends
 
 
struct product_t {
  long id;
  product_category_t category;
  product_u          p;
};
 
; -------------------------------------------------------------
product_t struc ; (sizeof=0x88)
id dd ?
category dd ?       ; enum product_category_t
p product_u ?
product_t ends
 
 
enum product_category_t {
  BOOK,
  SOFTWARE,
  HARDWARE
};

; -------------------------------------------------------------
; enum product_category_t
BOOK = 0
SOFTWARE = 1
HARDWARE = 2
 
 
 
struct software_info_t {
  unsigned int plateform : 2;
#define PC           0x1 // 0x01
#define MAC          0x2 // 0x02
  unsigned int os : 3;
#define WINDOWS      0x1 // 0x04
#define DOS          0x2 // 0x08
#define OS_X         0x4 // 0x10
  unsigned int category : 2;
#define DISASSEMBLY  0x1 // 0x20
#define RECOVERY     0x2 // 0x40
#define CRYPTOGRAPHY 0x3 // 0x60
};


; -------------------------------------------------------------
; enum software_info_t (bitfield)
 
PC = 1
MAC = 2
 
WINDOWS = 4
DOS = 8
OS_X = 10h
category       = 60h
DISASSEMBLY = 20h
RECOVERY = 40h
CRYPTOGRAPHY = 60h
 
 

; +------------------------------------------------------------+
; ¦This file is generated by The Interactive Disassembler (IDA)¦
; ¦Copyright (c) 2003 by DataRescue sa/nv, <ida@datarescue.com>¦
; ¦                      Licensed to: Eric <eric@datarescue.be>¦
; +------------------------------------------------------------+
;
; File Name   : C:\IDA\Presentations\Data\data.exe
; Format      : Portable executable for IBM PC (PE)
; Section 1. (virtual address 00001000)
; Virtual size                  : 00009000 (  36864.)
; Section size in file          : 00008E00 (  36352.)
; Offset to raw data for section: 00000600
; Flags 60000020: Text Executable Readable
; Alignment     : 16 bytes ?
 
 
unicode         macro page,string,zero
  irpc c,<string>
  db '&c', page
  endm
  ifnb <zero>
  dw zero
  endif
endm
 
 model flat
 
; --------------------------------------------------------------
 
; Segment type: Pure code
; Segment permissions: Read/Execute
_text segment para public 'CODE' use32
  assume cs:_text
  ;org 401000h
; [COLLAPSED AREA .text1. PRESS KEYPAD "+" TO EXPAND]
 
 
 
 
 
 
int check_software(software_info_t
 software_info)
{
 
   
  bool valid = true;



  if (software_info.plateform & PC)
  {

    if (! (software_info.plateform
           & MAC)



      && (software_info.os & OS_X))

        valid = false;
  }





  else if (software_info.plateform
           & MAC)
  {

    if (! (software_info.plateform
           & PC)



      && ((software_info.os
           & WINDOWS)



      || (software_info.os
          & DOS)))     


        valid = false;
  }


  else
    valid = false;






  return valid;
}
 
 
 
; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
 
 ; Attributes: bp-based frame
 
; int __cdecl check_software(software_info_t software_info)
check_software proc near ; CODE XREF: main+108p
 
software_info= byte ptr  8 
  push  ebp
  mov   ebp, esp
  mov   al, 1
  mov   dl, [ebp+software_info]
  and   edx, PC or MAC
  test  dl, PC
  jz    short not_PC
  mov   cl, [ebp+software_info]
  and   ecx, PC or MAC
  test  cl, MAC
  jnz   short end
  mov   dl, [ebp+software_info]
  shr   edx, 2
  and   edx, (WINDOWS or DOS or OS_X) >> 2
  test  dl, OS_X >> 2
  jz    short end
  xor   eax, eax
  jmp   short end
; --------------------------------------------------------------
 
not_PC:             ; CODE XREF: check_software+Ej
  mov   cl, [ebp+software_info]
  and   ecx, PC or MAC
  test  cl, MAC
  jz    short not_MAC
  mov   dl, [ebp+software_info]
  and   edx, PC or MAC
  test  dl, PC
  jnz   short end
  mov   cl, [ebp+software_info]
  shr   ecx, 2
  and   ecx, (WINDOWS or DOS or OS_X) >> 2
  test  cl, WINDOWS >> 2
  jnz   short not_windows
  mov   dl, [ebp+software_info]
  shr   edx, 2
  and   edx, (WINDOWS or DOS or OS_X) >> 2
  test  dl, DOS >> 2
  jz    short end
 
not_windows:        ; CODE XREF: check_software+4Fj
  xor   eax, eax
  jmp   short end
; --------------------------------------------------------------
 
not_MAC:            ; CODE XREF: check_software+36j
  xor   eax, eax
 
end:                ; CODE XREF: check_software+19j ...
  xor   edx, edx
  mov   dl, al
  mov   eax, edx
  pop   ebp
  retn
check_software endp
 
; --------------------------------------------------------------
  align 4
 
 
 
 
 
 
int check_product(product_category_t
 product_category)
{




  bool valid = true;
  if (product_category == HARDWARE)
  {
    valid = false;
    printf("We don't sell hardware
            for the moment...\n");
  }






  return valid;
}
 
; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
 
; Attributes: bp-based frame
 
; int __cdecl check_product(product_category_t product_category)
check_product proc near ; CODE XREF: print_product+Ap main+D8p
 
product_category= dword ptr  8
 
  push  ebp
  mov   ebp, esp
  push  ebx
  mov   bl, 1
  cmp   [ebp+product_category], HARDWARE
  jnz   short not_hardware
  xor   ebx, ebx
  push  offset aWeDonTSellHardwareForThe ; format
  call  _printf
  pop   ecx
 
not_hardware:       ; CODE XREF: check_product+Aj
  xor   eax, eax
  mov   al, bl
  pop   ebx
  pop   ebp
  retn
check_product endp            
 
 
 
 
 
 
void print_customer(customer_t *customer)
{









  printf("CUSTOMER %04X: %s (%c)\n",
    customer->id, customer->name,
    customer->sex);


}
 
; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
 
; Attributes: bp-based frame
 
; void __cdecl print_customer(customer_t *customer)
print_customer proc near ; CODE XREF: main+19p
 
customer= dword ptr  8
 
  push  ebp
  mov   ebp, esp
  mov   eax, [ebp+customer]
  movsx edx, byte ptr [eax+customer_t.sex]
  push  edx
  lea   ecx, [eax+customer_t.name]
  push  ecx
  push  [eax+customer_t.id]
  push  offset aCustomer04xSC ; format
  call  _printf
  add   esp, 10h
  pop   ebp
  retn
print_customer endp            
 
 
 
 
 
 
void print_book(book_t *book)
{






  printf("BOOK: %s\n", book->title);



}
 
 
 
; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
 
; Attributes: bp-based frame
 
; void __cdecl print_book(book_t *book)
print_book proc near ; CODE XREF: print_product+38p
 
book= dword ptr  8
 
  push  ebp
  mov   ebp, esp
  push  [ebp+book]
  push  offset aBookS ; format
  call  _printf
  add   esp, 8
  pop   ebp
  retn
print_book endp
 
; -------------------------------------------------------------
  align 4            
 
  
 
 
 
 
void print_software(software_t
 *software)
{










  printf("SOFTWARE: %s:",
   software->name);




  if (software->info.plateform & PC)


    printf(" PC");






  if (software->info.plateform & MAC)


    printf(" MAC");





  printf(";");





  if (software->info.os & WINDOWS)


    printf(" WINDOWS");







  if (software->info.os & DOS)


    printf(" DOS");







  if (software->info.os & OS_X)


    printf(" OS-X");





  printf(";");



  switch(software->info.category)
  {








    case DISASSEMBLY:


      printf(" DISASSEMBLY");

      break;


    case RECOVERY:


      printf(" RECOVERY");

      break;


    case CRYPTOGRAPHY:


      printf(" CRYPTOGRAPHY");
      break;

  }


  printf("\n");





}
 
 
 

; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
 
; Attributes: bp-based frame
 
; void __cdecl print_software(software_t *software)
print_software proc near ; CODE XREF: print_product+44p
 
software= dword ptr  8
 
  push  ebp
  mov   ebp, esp
  push  ebx
  push  esi
  mov   ebx, [ebp+software]
  mov   esi, offset aWeDonTSellHardwareForThe
  lea   eax, [ebx+software_t.name]
  push  eax
  lea   edx, (aSoftwareS - aWeDonTSellHardwareForThe)[esi]
  push  edx         ; format
  call  _printf
  add   esp, 8
  mov   cl, byte ptr [ebx+software_t.info]
  and   ecx, PC or MAC
  test  cl, PC
  jz    short not_pc
  lea   eax, (aPc - aWeDonTSellHardwareForThe)[esi]
  push  eax         ; format
  call  _printf
  pop   ecx
 
not_pc:
  mov   dl, byte ptr [ebx+software_t.info]
  and   edx, PC or MAC
  test  dl, MAC
  jz    short not_mac
  lea   ecx, (aMac - aWeDonTSellHardwareForThe)[esi]
  push  ecx         ; format
  call  _printf
  pop   ecx 
 
not_mac:
  lea   eax, (asc_40A31B - aWeDonTSellHardwareForThe)[esi]
  push  eax         ; format
  call  _printf
  pop   ecx
  mov   dl, byte ptr [ebx+software_t.info]
  shr   edx, 2
  and   edx, (WINDOWS or DOS or OS_X) >> 2
  test  dl, WINDOWS >> 2
  jz    short not_windows
  lea   ecx, (aWindows - aWeDonTSellHardwareForThe)[esi]
  push  ecx         ; format
  call  _printf
  pop   ecx
 
not_windows:
  mov   al, byte ptr [ebx+software_t.info]
  shr   eax, 2
  and   eax, (WINDOWS or DOS or OS_X) >> 2
  test  al, DOS >> 2
  jz    short not_dos
  lea   edx, (aDos - aWeDonTSellHardwareForThe)[esi]
  push  edx         ; format
  call  _printf
  pop   ecx
 
not_dos:
  mov   cl, byte ptr [ebx+software_t.info]
  shr   ecx, 2
  and   ecx, (WINDOWS or DOS or OS_X) >> 2
  test  cl, OS_X >> 2
  jz    short not_os_x
  lea   eax, (aOsX - aWeDonTSellHardwareForThe)[esi]
  push  eax         ; format
  call  _printf
  pop   ecx
 
not_os_x:
  lea   edx, (asc_40A331 - aWeDonTSellHardwareForThe)[esi]
  push  edx         ; format
  call  _printf
  pop   ecx
  mov   cl, byte ptr [ebx+software_t.info]
  shr   ecx, 5
  and   ecx, category >> 5
  dec   ecx
  jz    short DISASSEMBLY
  dec   ecx
  jz    short RECOVERY
  dec   ecx
  jz    short CRYPTOGRAPHY
  jmp   short end
; ------------------------------------------------------------
 
DISASSEMBLY:
  lea   eax, (aDisassembly - aWeDonTSellHardwareForThe)[esi]
  push  eax         ; format
  call  _printf
  pop   ecx
  jmp   short end
; ------------------------------------------------------------
 
RECOVERY:
  lea   edx, (aRecovery - aWeDonTSellHardwareForThe)[esi]
  push  edx         ; format
  call  _printf
  pop   ecx
  jmp   short end
; ------------------------------------------------------------
 
CRYPTOGRAPHY:
  lea   ecx, (aCryptography - aWeDonTSellHardwareForThe)[esi]
  push  ecx         ; format
  call  _printf
  pop   ecx
 
end:
  lea   eax, (asc_40A358 - aWeDonTSellHardwareForThe)[esi]
  push  eax         ; format
  call  _printf
  pop   ecx
  pop   esi
  pop   ebx
  pop   ebp
  retn
print_software endp 
 
; ------------------------------------------------------------
  align 4
 





bool print_product(product_t *product)
{







  if (! check_product(
        product->category))


    return false;







  printf("PRODUCT %04X: ",
   product->id);



  switch(product->category) {




    case BOOK:


      print_book(&product->p.book);

      break;


    case SOFTWARE:

      print_software(
       &product->p.software);
      break;

  }



  return true;
}
 
 
 
; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
 
; Attributes: bp-based frame
 
; int __cdecl print_product(product_t *product)
print_product proc near ; CODE XREF: main+128p
 
product= dword ptr  8
 
  push  ebp
  mov   ebp, esp
  push  ebx
  mov   ebx, [ebp+product]
  push  [ebx+product_t.category] ; product_category
  call  check_product
  pop   ecx
  test  eax, eax
  jnz   short check_product_ok
  xor   eax, eax
  pop   ebx
  pop   ebp
  retn
; ------------------------------------------------------------
 
check_product_ok:   ; CODE XREF: print_product+12j
  push  [ebx+product_t.id]
  push  offset aProduct04x ; format
  call  _printf
  add   esp, 8
  mov   edx, [ebx+product_t.category]
  sub   edx, 1
  jb    short case_book
  jz    short case_software
  jmp   short default
; ------------------------------------------------------------
 
case_book:          ; CODE XREF: print_product+2Ej
  add   ebx, product_t.p.book.title
  push  ebx         ; book
  call  print_book
  pop   ecx
  jmp   short default
; ------------------------------------------------------------
 
case_software:      ; CODE XREF: print_product+30j
  add   ebx, product_t.p.software.info
  push  ebx         ; software
  call  print_software
  pop   ecx
 
default:            ; CODE XREF: print_product+32j ...
  mov   al, 1
  pop   ebx
  pop   ebp
  retn
print_product endp 
 
; ------------------------------------------------------------
  align 4            
 
 
 
 
 
void main() {







  printf("CUSTOMERS:\n");

  customer_t *customer = customers;



  while (customer->id != 0)
  {
    print_customer(customer);

    customer++;



  }
  product_t *products = (product_t*)
    malloc(PRODUCTS_COUNT
    * sizeof(product_t));

  products[0].id         = 1;
  products[0].category   = BOOK;
  products[0].p.book     = ida_book;




  products[1].id         = 2;
  products[1].category   = SOFTWARE;
  products[1].p.software =
   softwares.softs[0];


  products[2].id         = 3;
  products[2].category   = SOFTWARE;
  products[2].p.software =
   softwares.softs[1];


  products[3].id         = 4;
  products[3].category   = SOFTWARE;
  products[3].p.software =
   softwares.softs[2];



  printf("\nPRODUCTS:\n");



  for (int i = 0;
   i < PRODUCTS_COUNT; i++)
  {


    if (! check_product(
     products[i].category))
    {


      printf("Invalid product !!!\n");

      break;
    }





    if (products[i].category
     == SOFTWARE)
    {



      if (! check_software(
        products[i].p.software.info))
      {

        printf("Invalid
                software !!!\n");

        break;
      }
    }




    print_product(&products[i]); 




  }


  free(products);





}
 
 
 
; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
 
; Attributes: bp-based frame
 
; void __cdecl main()
main proc near      ; DATA XREF: .data:0040A0D0o
  push  ebp
  mov   ebp, esp
  push  ebx
  push  esi
  push  edi
  push  offset aCustomers ; format
  call  _printf
  pop   ecx
  mov   ebx, offset customers
  jmp   short loc_401376
; ------------------------------------------------------------
 
loop_print_customer: ; CODE XREF: main+25j
  push  ebx         ; customer
  call  print_customer
  pop   ecx
  add   ebx, 40
 
loc_401376:         ; CODE XREF: main+16j
  cmp   [ebx+customer_t.id], 0
  jnz   short loop_print_customer
  push  544         ; size
  call  _malloc
  pop   ecx
  mov   ebx, eax
  mov   [ebx+product_t.id], 1
  xor   eax, eax    ; BOOK
  mov   [ebx+product_t.category], eax
  mov   esi, offset aIdaQuickstartG ; "IDA QuickStart Guide"
  lea   edi, [ebx+product_t.p.book.title]
  mov   ecx, 32
  rep movsd
  mov   dword ptr [ebx+product_t[1].id], 2
  mov   dword ptr [ebx+product_t[1].category], SOFTWARE
  mov   esi, offset softwares.softs
  lea   edi, [ebx+product_t[1].p.software]
  mov   ecx, 9
  rep movsd
  mov   dword ptr [ebx+product_t[2].id], 3
  mov   dword ptr [ebx+product_t[2].category], SOFTWARE
  mov   esi, (offset softwares.softs.info+24h)
  lea   edi, [ebx+product_t[2].p.software]
  mov   ecx, 9
  rep movsd
  mov   dword ptr [ebx+product_t[3].id], 4
  mov   dword ptr [ebx+product_t[3].category], SOFTWARE
  mov   esi, (offset softwares.softs.info+48h)
  lea   edi, [ebx+product_t[3].p.software]
  mov   ecx, 9
  rep movsd
  push  offset aProducts ; format
  call  _printf
  pop   ecx
  xor   esi, esi
 
loop_verify_print_product: ; CODE XREF: main+132j
  mov   eax, esi
  shl   eax, 4
  add   eax, esi
  push  [ebx+eax*8+product_t.category] ; product_category
  call  check_product
  pop   ecx
  test  eax, eax
  jnz   short product_is_valid
  push  offset aInvalidProduct ; format
  call  _printf
  pop   ecx
  jmp   short exit
; ------------------------------------------------------------ 
 
product_is_valid:   ; CODE XREF: main+E0j
  mov   edx, esi
  shl   edx, 4
  add   edx, esi
  cmp   [ebx+edx*8+product_t.category], SOFTWARE
  jnz   short print_product
  mov   ecx, esi
  shl   ecx, 4
  add   ecx, esi
  push  [ebx+ecx*8+product_t.p.software.info] ; software_info
  call  check_software
  pop   ecx
  test  eax, eax
  jnz   short print_product
  push  offset aInvalidSoftwar ; format
  call  _printf
  pop   ecx
  jmp   short exit
; -----------------------------------------------------------
 
print_product:      ; CODE XREF: main+FBj main+110j
  imul  eax, esi, 88h
  add   eax, ebx
  push  eax         ; product
  call  print_product
  pop   ecx
  inc   esi
  cmp   esi, 4
  jl    short loop_verify_print_product
 
exit:               ; CODE XREF: main+EDj main+11Dj
  push  ebx         ; block
  call  _free
  pop   ecx
  pop   edi
  pop   esi
  pop   ebx
  pop   ebp
  retn
main endp
 

; [COLLAPSED AREA .text2. PRESS KEYPAD "+" TO EXPAND]
; [COLLAPSED AREA .text2. PRESS KEYPAD "+" TO EXPAND]
; Section 2. (virtual address 0000A000)
; Virtual size                  : 00003000 (  12288.)
; Section size in file          : 00002800 (  10240.)
; Offset to raw data for section: 00009400
; Flags C0000040: Data Readable Writable
; Alignment     : 16 bytes ?
; ------------------------------------------------------------
 
; Segment type: Pure data
; Segment permissions: Read/Write
_data segment para public 'DATA' use32
  assume cs:_data
  ;org 40A000h
; [COLLAPSED AREA .data1. PRESS KEYPAD "+" TO EXPAND]
 
customer_t customers[] = {
  { 1,
    "Peter",
    'm' },
  { 2,
    "John",
    'm' },
  { 3,
    "Mary",
    'f' },
  { 0 }
};
 
 
 
 
customers dd 1              ; id ; DATA XREF: main+11o
  db 'Peter',0,0,0,0,0,0,0,0,0,0,0,0,0,0, ... ; name
  dd 'm'            ; sex
  dd 2              ; id
  db 'John',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,... ; name
  dd 'm'            ; sex
  dd 3              ; id
  db 'Mary',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,... ; name
  dd 'f'            ; sex
  dd 0              ; id
  db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ... ; name
  db 0              ; name
  dd 0              ; sex
 
book_t ida_book = { "IDA QuickStart
                     Guide" };

 
 
aIdaQuickstartG db 'IDA QuickStart Guide',0 ; DATA XREF: ...
  db 6Bh dup(0)
 
softwares_t softwares =
{
  3,
  { { { PC, WINDOWS|DOS,    
        DISASSEMBLY  },
      "IDA Pro" },
    { { PC|MAC, WINDOWS|OS_X,
        RECOVERY     },
      "PhotoRescue" },
    { { PC,     WINDOWS,    
        CRYPTOGRAPHY },
      "aCrypt" }
  }
};

 
 
 
softwares dd 3              ; count ; DATA XREF: main+62o
  dd PC or WINDOWS or DOS or DISASSEMBLY; softs.info
 
  db 'IDA Pro',0,0,0,0,0,0,0,0,0,0,0,0,0, ...; softs.name
  dd PC or MAC or WINDOWS or OS_X or RECOVERY; softs.info
 
  db 'PhotoRescue',0,0,0,0,0,0,0,0,0,0,0, ...; softs.name
  dd PC or WINDOWS or CRYPTOGRAPHY; softs.info
 
  db 'aCrypt',0,0,0,0,0,0,0,0,0,0,0,0,0,0,...; softs.name
  

aWeDonTSellHardwareForThe db 'We don',27h,'t sell hardware ...
                    ; DATA XREF: check_product+Eo ...
aCustomer04xSC db 'CUSTOMER %04X: %s (%c)',0Ah,0 ; ...
aBookS db 'BOOK: %s',0Ah,0 ; DATA XREF: print_book+6o
aSoftwareS db 'SOFTWARE: %s:',0 ; DATA XREF: ...
aPc db ' PC',0      ; DATA XREF: print_software+27r
aMac db ' MAC',0    ; DATA XREF: print_software+3Br
asc_40A31B db ';',0 ; DATA XREF: print_software+45r
aWindows db ' WINDOWS',0 ; DATA XREF: ...
aDos db ' DOS',0    ; DATA XREF: print_software+72r
aOsX db ' OS-X',0   ; DATA XREF: print_software+89r
asc_40A331 db ';',0 ; DATA XREF: print_software+93r
aDisassembly db ' DISASSEMBLY',0 ; DATA XREF: ...
aRecovery db ' RECOVERY',0 ; DATA XREF: ...
aCryptography db ' CRYPTOGRAPHY',0 ; DATA XREF: ...
asc_40A358 db 0Ah,0 ; DATA XREF: print_software+D8r
aProduct04x db 'PRODUCT %04X: ',0 ; DATA XREF: ...
aCustomers db 'CUSTOMERS:',0Ah,0 ; DATA XREF: ...
aProducts db 0Ah    ; DATA XREF: main+C0o
  db 'PRODUCTS:',0Ah,0
aInvalidProduct db 'Invalid product !!!',0Ah,0 ; ...
aInvalidSoftwar db 'Invalid software !!!',0Ah,0 ; ...

                                                                                                    TOP

 

附录

#include <stdio.h>

 

// our structures

// ==============

// information about our customers

struct customer_t { // a typical structure

long id;

char name[32];

char sex; // 'm'ale - 'f'emale

};

 

// we sell books

struct book_t {

char title[128]; // an ASCII string

};

// and we sell computer softwares

struct software_info_t { // a structure containing various bitfields

unsigned int plateform : 2; // 2 bits reserved for the plateform - plateforms can be combined (0x03)

#define PC 0x1 // 0x01

#define MAC 0x2 // 0x02

unsigned int os : 3; // 3 bits reserved for the OS - OS can be combined (0x1C)

#define WINDOWS 0x1 // 0x04

#define DOS 0x2 // 0x08

#define OS_X 0x4 // 0x10

unsigned int category : 2; // 2 bits reserved for the category - categories can't be combined (0x60)

#define DISASSEMBLY 0x1 // 0x20

#define RECOVERY 0x2 // 0x40

#define CRYPTOGRAPHY 0x3 // 0x60

};

struct software_t {

software_info_t info;

char name[32];

};

struct softwares_t { // a variable length structure to memorize our softwares

long count;

software_t softs[];

};

// generic products we're selling

enum product_category_t { // an enumerated type

BOOK,

SOFTWARE,

HARDWARE // we actually don't sell hardware

};

union product_u { // an union to contain product information depending on its category

book_t book;

software_t software;

// struct hardware_t hardware; // we actually don't sell hardware

};

struct product_t { // a structure containing another structure

long id;

product_category_t category;

product_u p;

};

 

// our data

// ========

// our customers

customer_t customers[] = { // an initialized array to memorize our customers

{ 1, "Peter", 'm' },

{ 2, "John", 'm' },

{ 3, "Mary", 'f' },

{ 0 }

};

// our products

book_t ida_book = { "IDA QuickStart Guide" };

softwares_t softwares = // an initialized variable length structure

{

3,

{

{ { PC, WINDOWS|DOS, DISASSEMBLY }, "IDA Pro" },

{ { PC|MAC, WINDOWS|OS_X, RECOVERY }, "PhotoRescue" },

{ { PC, WINDOWS, CRYPTOGRAPHY }, "aCrypt" }

}

};

#define PRODUCTS_COUNT 4

 

// our functions

// =============

// check software information

int check_software(software_info_t software_info)

{

bool valid = true;

if (software_info.plateform & PC)

{

if (! (software_info.plateform & MAC) && (software_info.os & OS_X))

valid = false; // OS-X isn't yet available on PC ;)

}

else if (software_info.plateform & MAC)

{

if (! (software_info.plateform & PC) && ((software_info.os & WINDOWS) || (software_info.os & DOS)))

valid = false; // Windows & DOS aren't available on Mac...

}

else

valid = false;

return valid;

}

 

// check product category

int check_product(product_category_t product_category)

{

bool valid = true;

if (product_category == HARDWARE)

{

valid = false;

printf("We don't sell hardware for the moment...\n");

}

return valid;

}

 

// print customer information

void print_customer(customer_t *customer)

{

printf("CUSTOMER %04X: %s (%c)\n", customer->id, customer->name, customer->sex);

}

 

// print book information

void print_book(book_t *book)

{

printf("BOOK: %s\n", book->title);

}

 

// print software information

void print_software(software_t *software)

{

printf("SOFTWARE: %s:", software->name);

// plateform

// we use 'if', as plateforms can be combined

if (software->info.plateform & PC)

printf(" PC");

if (software->info.plateform & MAC)

printf(" MAC");

printf(";");

// OS

// we use 'if', as os can be combined

if (software->info.os & WINDOWS)

printf(" WINDOWS");

if (software->info.os & DOS)

printf(" DOS");

if (software->info.os & OS_X)

printf(" OS-X");

printf(";");

// category

// we use 'switch', as categories can't be combined

switch(software->info.category)

{

case DISASSEMBLY:

printf(" DISASSEMBLY");

break;

case RECOVERY:

printf(" RECOVERY");

break;

case CRYPTOGRAPHY:

printf(" CRYPTOGRAPHY");

break;

}

printf("\n");

}

 

// print product information

bool print_product(product_t *product)

{

if (! check_product(product->category))

return false;

printf("PRODUCT %04X: ", product->id);

switch(product->category) {

case BOOK:

print_book(&product->p.book);

break;

case SOFTWARE:

print_software(&product->p.software);

break;

}

return true;

}

 

// our main program

// ================

void main() {

// print customers listing

printf("CUSTOMERS:\n");

customer_t *customer = customers;

while (customer->id != 0)

{

print_customer(customer);

customer++;

}

// allocate a small array to store our products in memory

product_t *products = (product_t*) malloc(PRODUCTS_COUNT * sizeof(product_t));

// insert our products

products[0].id = 1;

products[0].category = BOOK;

products[0].p.book = ida_book;

products[1].id = 2;

products[1].category = SOFTWARE;

products[1].p.software = softwares.softs[0]; // we insert softwares from our variable length structure

products[2].id = 3;

products[2].category = SOFTWARE;

products[2].p.software = softwares.softs[1];

products[3].id = 4;

products[3].category = SOFTWARE;

products[3].p.software = softwares.softs[2];

// verify and print each product

printf("\nPRODUCTS:\n");

for (int i = 0; i < PRODUCTS_COUNT; i++)

{

// check validity of the product category

if (! check_product(products[i].category))

{

printf("Invalid product !!!\n");

break;

}

// check validity of softwares

if (products[i].category == SOFTWARE)

{

if (! check_software(products[i].p.software.info))

{

printf("Invalid software !!!\n");

break;

}

}

// and print the product

print_product(&products[i]);

}

free(products);

}