Basic knowledge of Windows reverse security (1) (17)

pointer four

array of pointers

What is an array of pointers

First review the previous knowledge about arrays:

The so-called array is used to store the collection of the same data type

Combined with the previous knowledge about pointers: the essence of pointers is also a data type

So when the data type of the members stored in the array is a pointer, the array can be called a pointer array (essentially an array)

the code

#include "stdafx.h"
void function(){
    
    
        int** arr[5]={
    
    (int**)1,(int**)2,(int**)3,(int**)4,(int**)5};
}
int main(int argc, char* argv[])
{
    
    
        function();
        return 0;
}

disassembled code

9:        int** arr[5]={
    
    (int**)1,(int**)2,(int**)3,(int**)4,(int**)5};
00401038   mov         dword ptr [ebp-14h],1
0040103F   mov         dword ptr [ebp-10h],2
00401046   mov         dword ptr [ebp-0Ch],3
0040104D   mov         dword ptr [ebp-8],4
00401054   mov         dword ptr [ebp-4],5

small summary

  • It can be seen that there is nothing special about the pointer array, except that the data type of the stored array members is a pointer
  • The assignment of an array of pointers is also no different from the previous assignment of pointers

structure pointer

What is a structure pointer

The so-called structure pointer is to add several * after the structure to make it a pointer type

the code

#include "stdafx.h"
#include <typeinfo>

struct S1{
    
    
        int a;
};

void function(){
    
    
        S1* s1=(S1*)0x12345678;
    printf("%x\n",s1);
}
int main(int argc, char* argv[])
{
    
    
        function();
        return 0;
}

operation result

insert image description here
Result analysis

It can be seen that the use of structure pointers here seems to be no different from ordinary pointers, but at this time you will find that there are no members inside the structure yet.

So the actual use of the structure pointer is not like this, let's look at a wrong example

error code

void function(){
    
    
        S1* s1=(S1*)0x12345678;
    int a=s1->a;
}

Just add a statement to read the members of the structure on the basis of the above code, and check the running results

operation result

insert image description here

The result of the operation went wrong as expected, and the cause of the error began to be analyzed

disassembled code

14:       S1* s1=(S1*)0x12345678;
00401038   mov         dword ptr [ebp-4],12345678h
15:       int a=s1->a;
0040103F   mov         eax,dword ptr [ebp-4]
00401042   mov         ecx,dword ptr [eax]
00401044   mov         dword ptr [ebp-8],ecx

Disassembly analysis

0. The state of s1 and s1->a before execution

s1:

insert image description here
s1->a:

insert image description here
1. Assign a value to the structure pointer s1

14:       S1* s1=(S1*)0x12345678;
00401038   mov         dword ptr [ebp-4],12345678h

insert image description here
Now look at s1->a:

insert image description here
It can be found that the assignment operation to s1 does not change the value of s1->a, but changes the address of s1->a

In fact, it can be seen from the state of s1 and s1->a before execution that the content stored in s1 is not directly storing the content of the structure member, but storing the address pointing to the structure member

So here, only the address of the member is changed for the previous assignment operation of s1, but the value of the member is not changed

And at the beginning, the structure members were not assigned the corresponding memory address

2. Visit s1->a

15:       int a=s1->a;
0040103F   mov         eax,dword ptr [ebp-4]
00401042   mov         ecx,dword ptr [eax]
00401044   mov         dword ptr [ebp-8],ecx

The reason for the error is obvious at this time. The previous assignment operation to s1 modified the address of s1->a, making it point to an inaccessible address, resulting in an error

correct code

We already know that the reason for the error is that the access to an inaccessible address caused an error, and the structure members were not assigned the corresponding memory address at the beginning

So you just need to manually allocate the memory address for the structure members, here we will use the malloc function to allocate the memory address

malloc function

void *malloc(size_t size)

Parameters: size, the size of the memory block, in bytes

Return value: Returns a pointer to the memory of the allocated size. Returns NULL if the request fails

Related header files: malloc.h, alloc.h, stdlib.h

After a general understanding of the malloc function, let's look at the code:

#include "stdafx.h"
#include <malloc.h>                //这里使用了malloc.h
struct S1{
    
    
    int a;
        int b;
        int c;
};
void function(){
    
    
        S1* s1=(S1*) malloc(sizeof(S1));        //申请一块空间大小正好为S1大小的内存
        s1->a=610;
        s1->b=666;
        s1->c=52;
        printf("%d\n",s1->a);
        printf("%d\n",s1->b);
        printf("%d\n",s1->c);
}
int main(int argc, char* argv[])
{
    
    
        function();
        return 0;
}

operation result

insert image description here

You can see that the members of the structure can be rewritten and accessed normally

disassembled code

15:       S1* s1=(S1*) malloc(sizeof(S1));
0040D778   push        0Ch
0040D77A   call        malloc (00401150)
0040D77F   add         esp,4
0040D782   mov         dword ptr [ebp-4],eax
16:       s1->a=610;
0040D785   mov         eax,dword ptr [ebp-4]
0040D788   mov         dword ptr [eax],262h
17:       s1->b=666;
0040D78E   mov         ecx,dword ptr [ebp-4]
0040D791   mov         dword ptr [ecx+4],29Ah
18:       s1->c=52;
0040D798   mov         edx,dword ptr [ebp-4]
0040D79B   mov         dword ptr [edx+8],34h

Disassembly analysis

1. First look at this malloc function

15:       S1* s1=(S1*) malloc(sizeof(S1));
0040D778   push        0Ch
0040D77A   call        malloc (00401150)
0040D77F   add         esp,4
0040D782   mov         dword ptr [ebp-4],eax
  1. The parameter 0C is pressed, corresponding to 12 in decimal, which is the size of S1
  2. call malloc function
  3. off-stack balance
  4. Assign the return value eax to S1

Look at the content of the return value eax:

insert image description here

You can see that eax corresponds to the members in the structure

eax=the first address of the structure member, the structure members inside are stored continuously

2. Assignment, assign 610 corresponding to hexadecimal 262 to [eax], corresponding to the previous 003807B8

16:       s1->a=610;
0040D785   mov         eax,dword ptr [ebp-4]
0040D788   mov         dword ptr [eax],262h

After execution:

insert image description here
3. Assignment, assign 666 corresponding to hexadecimal 29A to [ecx+4], corresponding to the previous 003807BC

17:       s1->b=666;
0040D78E   mov         ecx,dword ptr [ebp-4]
0040D791   mov         dword ptr [ecx+4],29Ah

After execution:

insert image description here
4. Assignment, assign 52 corresponding to hexadecimal 34 to [edx+4], corresponding to the previous 003807C0

18:       s1->c=52;
0040D798   mov         edx,dword ptr [ebp-4]
0040D79B   mov         dword ptr [edx+8],34h

After execution:

insert image description here

small summary

  • Struct pointers are not really that different from normal pointers

  • When operating on structure members, it needs to be initialized first (allocate memory address for each structure member)

  • The structure pointer does not directly store the structure members, but stores the address pointing to the structure members, which stores all the structure members

array pointer

I learned the pointer array before, and now I have an array pointer, and the transition is made with the structure pointer in the middle to avoid confusion

What is an array pointer

The so-called array pointer is a pointer to an array (essentially a pointer)

Since it is a pointer, it naturally satisfies all the characteristics of the previous pointer: pointer assignment, pointer data width, pointer addition and subtraction, pointer type subtraction, pointer comparison

Declaration of array pointer

int (*px)[2];

As stated above, the array pointer variable is px, and its type is: int(*)[2]; the array pointed to by the array pointer is int[2]

The difference between an array pointer and a pointer to an array

the code

#include "stdafx.h"

void function(){
    
    
        int arr[6]={
    
    1,2,3,4,5,6};
        //声明一个数组指针,该指针指向数组为:int[2]
        int (*px)[2];        
        //给数组指针赋值,使该数组指针指向arr数组的首地址
        px=(int (*)[2]) &arr[0];
        //用一个临时变量parr2 存储数组指针
        int (*parr2)[2]=px;
    //*px为数组的首地址,也就是arr,这里就相当于int* arr2=arr;此时的arr2就是指向数组的指针
        int* arr2=*px;
    //初始化变量,准备循环
    int i;
    //循环遍历数组
        for(i=0;i<6;i++){
    
    
                printf("%x\t%d\n",arr2+i,arr2[i]);
        }
        printf("\n");        
        int a=(int) (parr2+1);
        int b=(int) (arr2+1);
        printf("%x\t%x\n",a,b);   
}
int main(int argc, char* argv[])
{
    
    
        function();
        return 0;
}

operation result

insert image description here
First you can see the normal traversal of the array

Then output the results of parr2+1 and arr2+1 respectively, note that the results here are different

disassembled code

8:        int arr[6]={
    
    1,2,3,4,5,6};
00401038   mov         dword ptr [ebp-18h],1
0040103F   mov         dword ptr [ebp-14h],2
00401046   mov         dword ptr [ebp-10h],3
0040104D   mov         dword ptr [ebp-0Ch],4
00401054   mov         dword ptr [ebp-8],5
0040105B   mov         dword ptr [ebp-4],6
9:
10:       int (*px)[2];
11:
12:       px=(int (*)[2]) &arr[0];
00401062   lea         eax,[ebp-18h]
00401065   mov         dword ptr [ebp-1Ch],eax
13:
14:       int (*parr2)[2]=px;
00401068   mov         ecx,dword ptr [ebp-1Ch]
0040106B   mov         dword ptr [ebp-20h],ecx
15:       int* arr2=*px;
0040106E   mov         edx,dword ptr [ebp-1Ch]
00401071   mov         dword ptr [ebp-24h],edx
16:
17:       int i;
18:
19:       for(i=0;i<6;i++){
    
    
00401074   mov         dword ptr [ebp-28h],0
0040107B   jmp         function+66h (00401086)
0040107D   mov         eax,dword ptr [ebp-28h]
00401080   add         eax,1
00401083   mov         dword ptr [ebp-28h],eax
00401086   cmp         dword ptr [ebp-28h],6
0040108A   jge         function+8Fh (004010af)
20:           printf("%x\t%d\n",arr2+i,arr2[i]);
0040108C   mov         ecx,dword ptr [ebp-28h]
0040108F   mov         edx,dword ptr [ebp-24h]
00401092   mov         eax,dword ptr [edx+ecx*4]
00401095   push        eax
00401096   mov         ecx,dword ptr [ebp-28h]
00401099   mov         edx,dword ptr [ebp-24h]
0040109C   lea         eax,[edx+ecx*4]
0040109F   push        eax
004010A0   push        offset string "%x\t%d\n" (00422024)
004010A5   call        printf (00401160)
004010AA   add         esp,0Ch
21:       }
004010AD   jmp         function+5Dh (0040107d)
22:       printf("\n");
004010AF   push        offset string "\n" (00422020)
004010B4   call        printf (00401160)
004010B9   add         esp,4
23:
24:       int a=(int) (parr2+1);
004010BC   mov         ecx,dword ptr [ebp-20h]
004010BF   add         ecx,8
004010C2   mov         dword ptr [ebp-2Ch],ecx
25:       int b=(int) (arr2+1);
004010C5   mov         edx,dword ptr [ebp-24h]
004010C8   add         edx,4
004010CB   mov         dword ptr [ebp-30h],edx
26:       printf("%x\t%x\n",a,b);
004010CE   mov         eax,dword ptr [ebp-30h]
004010D1   push        eax
004010D2   mov         ecx,dword ptr [ebp-2Ch]
004010D5   push        ecx
004010D6   push        offset string "%x\t%x\n" (00422fa4)
004010DB   call        printf (00401160)
004010E0   add         esp,0Ch

Disassembly analysis
1. Array initialization

8:        int arr[6]={
    
    1,2,3,4,5,6};
00401038   mov         dword ptr [ebp-18h],1
0040103F   mov         dword ptr [ebp-14h],2
00401046   mov         dword ptr [ebp-10h],3
0040104D   mov         dword ptr [ebp-0Ch],4
00401054   mov         dword ptr [ebp-8],5
0040105B   mov         dword ptr [ebp-4],6

After the array is initialized, the corresponding address and content are:

insert image description here
2. Assignment of array pointer

12:       px=(int (*)[2]) &arr[0];
00401062   lea         eax,[ebp-18h]
00401065   mov         dword ptr [ebp-1Ch],eax

Directly pass the first address of the arr array, which is 0012FF14, to eax

Then assign eax to the value pointer px

After value pointer assignment:

insert image description here
You can see that the content stored in the value pointer is 0012FF14, which is the address of arr

3. Assign the value pointer px to another array pointer parr2

14:       int (*parr2)[2]=px;
00401068   mov         ecx,dword ptr [ebp-1Ch]
0040106B   mov         dword ptr [ebp-20h],ecx

After assignment:

insert image description here
You can see that the content stored in parr2 = the content stored in px = 0012FF14 = the first address of arr

4. Assign the first address of the array to arr2, that is, arr2=arr

14:       int* arr2=*px;
0040D82E   mov         edx,dword ptr [ebp-1Ch]
0040D831   mov         dword ptr [ebp-24h],edx

It should be noted here that it is assigned as before [ebp-1Ch]

That is to say, the assignment is *px, but the assignment is the same as px

It can also be concluded that px=px, so why are px and px the same**?

First of all, it must be clear whether it is px or *px, they are all pointers, one is an array pointer, and the other is an ordinary pointer

The addresses they point to are the same, both point to the first address 0012FF14 of arr

The essence of the difference between px and *px is that its data types are two different pointer structures

When pointers are added and subtracted, the basic unit of addition and subtraction is the data width of the pointer minus one *

  • The data type of px is: int ( )[2], after removing one, it becomes int [2], and the data width is the data width of int × the number of members of the array=4*2=8
  • The data type of px is: int , remove one * and become int, data width=4

After assignment:
insert image description here
5. Loop through the array

It is an ordinary circular array of pointers, which has been introduced in detail in the previous article, so I won’t go into details here

6. The second cycle

24:       int a=(int) (parr2+1);
004010BC   mov         ecx,dword ptr [ebp-20h]
004010BF   add         ecx,8
004010C2   mov         dword ptr [ebp-2Ch],ecx
25:       int b=(int) (arr2+1);
004010C5   mov         edx,dword ptr [ebp-24h]
004010C8   add         edx,4
004010CB   mov         dword ptr [ebp-30h],edx

It can be known from the front that *px=px, parr2=arr2, so [ebp-20h]=[ebp-24h] here:

insert image description hereThe difference here is that one adds 8 and the other adds 4, which is consistent with the unit of pointer addition and subtraction analyzed earlier, so different results are produced

small summary

  • Add * before an array pointer to get a pointer to the array, such as int arr2=px in the above example;
  • The content stored in the value pointer and the pointer to the array is the first address of the array, such as px=*px=arr=0012FF14 in the above example
  • The main difference between an array pointer and a pointer to an array is the unit of operation. The former is the data type width × the number of array members, and the latter is the data type width

Application of array pointer

You can use the different units when adding and subtracting array pointers to traverse the fixed interval members of the array

The following example starts from the second member of the array and extracts the array members whose interval is 3

the code

#include "stdafx.h"
void function(){
    
    
        int arr[15]={
    
    1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

        int (*px)[3];        
        //从数组的第二个成员开始
        px=(int (*)[3]) &arr[1];

        int i=0;
        for(i=0;i<15/3;i++){
    
    
                printf("%x\t%d\n",px+i,**(px+i));
        //注意这里取了两次*,第一次获得的是指向数组成员的指针,第二个获得的才是数组成员
        }
}
int main(int argc, char* argv[])
{
    
    
        function();
        return 0;
}

operation result

insert image description here

Summarize

insert image description here

Guess you like

Origin blog.csdn.net/qq_64973687/article/details/130342461