结构体链表逆向
同样使用如下的C代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct _student
{
char name[32];
int age;
struct _student * next;
}T_student;
T_student * head = NULL;
void Insert(const char *name,int age)
{
T_student * newnode;
newnode = (T_student *)malloc(sizeof(T_student));
newnode->age = age;
newnode->next = head;
strcpy(newnode->name,name);
head = newnode;
}
void PrintStudent()
{
T_student * tmp;
tmp = head;
while(tmp)
{
printf("name:%s age:%d\n",tmp->name,tmp->age);
tmp=tmp->next;
}
}
int main()
{
Insert("Panda",15);
Insert("Dog",3);
Insert("Cat",2);
Insert("XiaoMing",20);
PrintStudent();
}
按照惯例,编译把文件丢到IDA,找到main函数,点开。可以看到调用了四次insert函数和PrintStudent函数。
点到insert函数中查看函数实现。传入两个参数后,后面调用了malloc函数来分配内存空间,R3就可以看做是malloc分配来的内存并且指向此块内存的指针。其后使用dest来表示这个指针。var_14把内存数据存入dest加偏移量为32的地址上。也就是把第二个int参数存入相应地址。获取head变量,LDR把head变量当作地址来加载其上的数据,head同样可能是指针。而后会把第一个参数和head指针数据同样存入到结构体对应的地址上。只是第一个参数使用了strcpy来复制,顺便一提可能会产生数据覆盖。最后指针dest存到head的地址上,由head来表示基地址。
后面再看一下PrintStudent函数。将head的地址值存到新的指针中。以下仍然使用*head表示存入的地址上的数据。判断值为指针是否为0,从而进行遍历,到此为止基本可以看到前面的结构体存入参数和head赋值,完成了一个链表的结构。此处是遍历链表判断是否遍历完成。
获取到第一个第二个参数后,var_8指针由参数三来进行下一个结构体的查询。
实现大致如下,当执行第一次insert函数时,写入一个结构体,并且把结构体的基地址写入head指针,第二次执行insert函数时,把head指针写入第二个结构体的第三个参数也就是结构体的指向下一个节点的指针。完成一个链表的创建。按照执行顺序,从后往前执行,第三个参数也就是节点的指针是前一个结构体的基地址。直到遍历完成,指针为null。
至此,结构体链表的分析就算完成了。无名侠的这个课程也算是结束了,不得不说多看几遍还是有不少的收获。