【黑客免杀攻防】读书笔记12 - 指针与数组

1、指针与数组

C源码

前两组printf()函数是以指针方式访问数组nArray中的数据的,而后两组printf()函数则是使用数组下标的方式访问数组nArray中的数据的。

int _tmain(int argc, _TCHAR* argv[])
{
    // 数组赋值
    int  nArray[3] = {0x10,0x20,0x300};
    // 数组地址赋值给指针
    int *pPtr      = nArray;

    // 输出指针中地址
    printf("%x %x %x\r\n", pPtr+0, pPtr+1, pPtr+2);
    // 输出指针指向的值
    printf("%x %x %x\r\n", *(pPtr+0), *(pPtr+1), *(pPtr+2));
    // 输出数组中的地址
    printf("%x %x %x\r\n", &nArray[0], &nArray[1], &nArray[2]);
    // 输出数组中的值
    printf("%x %x %x\r\n", nArray[0], nArray[1], nArray[2]);

    return 0;
}

Debug汇编

对比指针访问和数组访问的汇编,发现用指针访问是向后移动长度为一个int大小的距离,也就是4字节。

至于加8是因为指针的运算时以指针类型为依据的。

003CC55E mov [local.4],0x10
003CC565 mov [local.3],0x20
003CC56C mov [local.2],0x300
003CC573 lea eax,[local.4]
003CC576 mov [local.7],eax
003CC579 mov eax,[local.7]
003CC57C add eax,0x8                              ;  pPtr+2
003CC57C                                          ;  C语言中,指针的运算是以指针类型为依据的
003CC57C                                          ;  一个int型指针加1,就是将其指向的地址向后移动长度为一个
003CC57C                                          ; int大小的距离,也就是4字节。如果是Word型,那就向后移动2字节。
003CC57F push eax
003CC580 mov ecx,[local.7]
003CC583 add ecx,0x4                              ;  pPtr+1
003CC586 push ecx
003CC587 mov edx,[local.7]
003CC58A push edx                                 ;  pPtr+0
003CC58B push 9-44.00420C6C                       ;  ASCII "%x %x %x\r\n"
003CC590 call 9-44.003CB0B3
003CC595 add esp,0x10
003CC598 mov eax,[local.7]                        ;  *(pPtr+2)
003CC59B mov ecx,dword ptr ds:[eax+0x8]
003CC59E push ecx
003CC59F mov edx,[local.7]                        ;  *(pPtr+1)
003CC5A2 mov eax,dword ptr ds:[edx+0x4]
003CC5A5 push eax
003CC5A6 mov ecx,[local.7]
003CC5A9 mov edx,dword ptr ds:[ecx]
003CC5AB push edx
003CC5AC push 9-44.00420C6C                       ;  ASCII "%x %x %x\r\n"
003CC5B1 call 9-44.003CB0B3
003CC5B6 add esp,0x10
003CC5B9 lea eax,[local.2]                        ;  &nArray[2]
003CC5BC push eax
003CC5BD lea ecx,[local.3]                        ;  &nArray[1]
003CC5C0 push ecx
003CC5C1 lea edx,[local.4]                        ;  &nArray[0]
003CC5C4 push edx
003CC5C5 push 9-44.00420C6C                       ;  ASCII "%x %x %x\r\n"
003CC5CA call 9-44.003CB0B3
003CC5CF add esp,0x10
003CC5D2 mov eax,[local.2]                        ;  nArray[2]
003CC5D5 push eax
003CC5D6 mov ecx,[local.3]                        ;  nArray[1]
003CC5D9 push ecx
003CC5DA mov edx,[local.4]                        ;  nArray[0]
003CC5DD push edx
003CC5DE push 9-44.00420C6C                       ;  ASCII "%x %x %x\r\n"
003CC5E3 call 9-44.003CB0B3
003CC5E8 add esp,0x10
003CC5EB xor eax,eax

Release汇编

发布版的的汇编指令和debug版本相比会做一些优化的操作。

使用指针取数据和数组取数据的反汇编代码是完全相同的。

011D1000 sub esp,0xC
011D1003 lea eax,dword ptr ss:[esp+0x8]           ;  pPtr+2
011D1007 push eax
011D1008 lea ecx,dword ptr ss:[esp+0x8]           ;  pPtr+1
011D100C push ecx
011D100D lea edx,dword ptr ss:[esp+0x8]           ;  pPtr+0
011D1011 push edx
011D1012 push 9-44.011DB384                       ;  ASCII 25,"x %x %x\r\n"
011D1017 mov dword ptr ss:[esp+0x10],0x10         ;  存放值
011D101F mov dword ptr ss:[esp+0x14],0x20
011D1027 mov dword ptr ss:[esp+0x18],0x300
011D102F call 9-44.printfc_crttProcess4lockonFilt>
011D1034 mov eax,dword ptr ss:[esp+0x18]          ;  *(pPtr+2)
011D1038 mov ecx,dword ptr ss:[esp+0x14]          ;  *(pPtr+1)
011D103C mov edx,dword ptr ss:[esp+0x10]          ;  *(pPtr+0)
011D1040 push eax
011D1041 push ecx
011D1042 push edx
011D1043 push 9-44.011DB384                       ;  ASCII 25,"x %x %x\r\n"
011D1048 call 9-44.printfc_crttProcess4lockonFilt>
011D104D lea eax,dword ptr ss:[esp+0x28]          ;  &nArray[2]
011D1051 push eax
011D1052 lea ecx,dword ptr ss:[esp+0x28]          ;  &nArray[1]
011D1056 push ecx
011D1057 lea edx,dword ptr ss:[esp+0x28]          ;  &nArray[0]
011D105B push edx
011D105C push 9-44.011DB384                       ;  ASCII 25,"x %x %x\r\n"
011D1061 call 9-44.printfc_crttProcess4lockonFilt>
011D1066 mov eax,dword ptr ss:[esp+0x38]          ;  nArray[2]
011D106A mov ecx,dword ptr ss:[esp+0x34]          ;  nArray[1]
011D106E mov edx,dword ptr ss:[esp+0x30]          ;  nArray[0]
011D1072 push eax
011D1073 push ecx
011D1074 push edx
011D1075 push 9-44.011DB384                       ;  ASCII 25,"x %x %x\r\n"
011D107A call 9-44.printfc_crttProcess4lockonFilt>

1.1 数组的不同表达方式

数组在反汇编中的表达方式一般分为一维数组、二维数组、多维数组这三种,其中一维数组和多维数组是比较难以区分的,但是可以从代码结构和逻辑着手,进而分析出这是一个几维数组。

在数组面对循环访问的情况下,负责控制访问数组成员偏移的功能由一个寄存器作为选择子来代替。

数组的访问会遵循以下公式:

数组成员地址 = 数组起始地址 + sizeof(数组类型) X 数组成员下标

2 数组与结构体

数组与结构体存放数据的原则都是一样的,它们都是在一段连续的空间中存放若干数据,唯一的不同之处在于数组存放的数据都是同一类型的,而结构体则有可能存放多种类型的数据。

C源代码


int _tmain(int argc, _TCHAR* argv[])
{
    struct _TEST
    {
        int    nNum;
        double dFloat;
        char   szStr[0x10];
    }stcTEST;
    stcTEST.nNum   = 0xAAAA;
    stcTEST.dFloat = 12.345;
    strcpy_s(stcTEST.szStr,"Hello World!");

    printf("%X %f %s",stcTEST.nNum,stcTEST.dFloat,stcTEST.szStr);

    return 0;
}

这里的代码没看明白

movsd   xmm0, ds:qword_416490 ; 将12.345保存到浮点寄存器中
lea     eax, [esp+44h+var_18]
add     esp, 4
mov     [esp+40h+var_28], 0AAAAh
movsd   [esp+40h+var_20], xmm0
push    offset aHelloWorld ; "Hello World!"
push    10h
push    eax
call    sub_403A3F      ; strcpy函数
movsd   xmm0, [esp+4Ch+var_20]
lea     eax, [esp+4Ch+var_18]
add     esp, 0Ch
push    eax
sub     esp, 8          ; 空出8字节空间保存double
movsd   [esp+4Ch+var_4C], xmm0
push    [esp+4Ch+var_28]
push    offset aXFS     ; "%X %f %s"
call    sub_401090

数组是一组同类型的被连续保存的数据,而结构体也有可能与数组一样。结构体的反汇编特征与数组一致。我理解为两者都是内存里开辟了一串连续的存储空间,然后把数据根据数据类型大小存放。

原文地址:https://www.cnblogs.com/17bdw/p/8287542.html

时间: 2024-07-31 18:25:36

【黑客免杀攻防】读书笔记12 - 指针与数组的相关文章

《C++ Primer 4th》读书笔记 第4章-数组和指针

原创文章,转载请注明出处: http://www.cnblogs.com/DayByDay/p/3911573.html <C++ Primer 4th>读书笔记 第4章-数组和指针

PHP读书笔记(6)- 数组

数组定义 数组就是一个键值对组成的语言结构,键类似于酒店的房间号,值类似于酒店房间里存储的东西.PHP 中的数组实际上是一个有序映射.映射是一种把 values 关联到 keys 的类型. 定义数组 array() 可以用 array() 语言结构来新建一个数组.它接受任意数量用逗号分隔的 键(key) => 值(value)对. array( key => value , ... ) // 键(key)可是是一个整数 integer 或字符串 string // 值(value)可以是任意类

C语言学习笔记(六) 指针和数组

使用C语言就必然会使用到指针和数组.看下面的代码: int main(int argc, char** argv){     int a[4] = {1,3,5,7};     int *p = a;     int i;     for (i=0; i<4;i++){         printf("i=%d, p[i]=%d, *(p+i)=%d, a[i]=%d, *(a+i)=%d\n",                 i, p[i], *(p+i), a[i], *(

《C程序设计语言》笔记 (五) 指针与数组

5.1 指针与地址 指针是一种保存变量地址的变量 ANSI C使用类型void*(指向void的指针)代替char *作为通用指针的类型 一元运算符&可用于取一个对象的地址: p = &c 把C的地址赋值给变量p,我们称p为指向c的指针.地址运算符&只能应用于内存中的对象,即变量与数组元素. 不能作用于表达式 常量或register变量 一元运算符*是间接寻址或间接引用运算符.当它作用于指针时,将访问指针所指向的对象 由于指针也是变量,所以在程序中可以直接使用,而不必通过间接引用的

&lt;C和指针---读书笔记12&gt;

Struct. 有时候我们希望把归属于一类的信息放在一起,便于查看.如一个员工的姓名.编号.工资.出勤.它又 字符串.int.float.数组等 构成.C提供了struct,使他们聚合在一起,便于我们访问. 结构定义 很显然,结构也是一个变量,它有自己的变量名,类型是struct;除此之外,我们还要说明 它由什么构成. (1)  struct  { member list }  x; 这个跟 int x一样,声明一个int型变量x.此处,声明一个 由member_list 组合构成的struct

《C++Primer4th》读书笔记第4章-数组和指针

昏君不去说几个明君也是至多盯着甲胄锻炼恨不得今日花钱明日便可立竿见影为臣 比如他听说正值乱世偏偏西北凉州即将有一桩婚嫁喜事. 潭狐 岸妍萼 翁之意不在酒的访客她也仅是以小院子女主人的身份略微露面勉强不失礼仪再无更多 徐凤年对糜奉节说道:"随便跟阮岗知会一声就说明天我去他家登门拜访让他备好美酒 耽脖孔 徐北枳很快就接话道:"是啊如同张巨鹿身在离阳未必就肯事事为赵室一家一姓考虑 当李十月望见那座派头吓人的经略使府邸看到一本正经穿上正二品文官补服的老人拉住新 抖蘊匙惺厝衣順腥了糯睾量

大话设计模式读书笔记--12.状态模式

定义 状态模式定义: 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来改变了其类 消除庞大的条件分支,将特定状态的行为放入一个对象中 生活中:开灯和关灯是两个状态 模式结构 Context: 上下文环境,维护一个状态实例,定义当前的状态 State: 抽象状态类,定义一个接口,封装与Context的一个特定状态相关的行为 ConcreteState:具体状态.实现Context的一个特定状态相关的行为 代码实现 场景: 12店之前是休闲状态, 之后是忙碌状态 点击下载代码 特点及使用场

《黑客与画家》读书笔记

趋同性 一群孩子结伙欺负你,并不是你做错了什么,而是因为这伙人需要找一件事一起干,:他们实际上并不恨你,他们只是需要一个共同的目标: 使用毒品基于同样的道理: 怪人使用毒品,是为了建立他们之间的社会纽带: 因为毒品是非法的,所以一起使用的话,就创造出一种共同的反叛感: 老员工与新人的关系 如果存在真正的外部能力测试,那么待在等级关系的底层也不会那么痛苦: 球队的新人不会怨恨老队员的球技,他希望自己有一天也能如何,所以很高兴有机会就向老队员请教:老队员也因此产生传帮带的光荣感: 最重要的是,老队员

《黑客与画家》读书笔记1

午休的时候,读者本书,提到一个概念,大学把黑客变成科学家,去写论文.企业把黑客变成工程师,当成一个技工使用. 前者我不太能切身的体会到,后者我是非常赞同的. 作者,经历过两个过程,非常讨厌,认为黑客应该优雅的编写一个软件,或者设计一个软件.就像企业的产品,应该交由黑客去设计,和开发.而并不是交给一堆产品经理去设计,然后交给黑客们去翻译成代码.因为做过开发的经历,我能非常的明白这样一个体会.产品经理设计的东西真的愚蠢无比.技术人员的天生骄傲,就能狠狠的鄙视你. 但是是真的么.no,所有的黑客,这非