轻量级json解析库cJSON的使⽤与fuzz测试
0x10 cJSON 介绍
0x11 项⽬简介不属于javascript关键字
Json作为⼀种轻量级的⽂本数据交换格式,⼴为应⽤,虽然是JavaScript语⾔中,出现的⼀个⼦集,但是早已成为独⽴的语⾔格式。其语法格式,类似于Python中的字典。然⽽,C语⾔原⽣并不⽀持字典,更不⽤说对Json⽂件的解析了。
cJSON的使⽤⽅式也较为简单,主要有以下两种⽅式:
源码编译⽣成 libcjson.so
直接将 cJSON.c cJSON.h 复制到⾃⼰的项⽬⾥
0x12 典型源码说明
cJSON定义的数据结构,从下⾯的代码 cJSON.c 不难看出,cJSON 使⽤链表的⽅式存储
typedef struct cJSON {
struct cJSON *next,*prev;/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child;/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type;/* The type of the item, as above. cjson结构的类型上⾯宏定义的7中之⼀*/
char*valuestring;/* The item's string, if type==cJSON_String */
int valueint;/* The item's number, if type==cJSON_Number */
double valuedouble;/* The item's number, if type==cJSON_Number */
char*string;/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
解析json⽤到的函数(头⽂件 cjson.h 定义),这也是我们在项⽬中经常⽤到的⼀些函数
extern cJSON *cJSON_Parse(const char*value);//从给定的json字符串中得到cjson对象
extern char*cJSON_Print(cJSON *item);//从cjson对象中获取有格式的json对象
extern char*cJSON_PrintUnformatted(cJSON *item);//从cjson对象中获取⽆格式的json对象
extern void cJSON_Delete(cJSON *c);//删除cjson对象,释放链表占⽤的内存空间
sprintboot实现视频播放
extern int cJSON_GetArraySize(cJSON *array);//获取cjson对象数组成员的个数
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);//根据下标获取cjosn对象数组中的对象
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char*string);//根据键获取对应的值(cjson对象)
extern const char*cJSON_GetErrorPtr(void);//获取错误字符串
0x20 使⽤cJSON解析json⽂件
将github中的 cJSON.c cJSON.h 拷贝到⾃⼰的项⽬中,即可使⽤。在笔者实践过程中,绕了不少弯路,主要是由于,对json⽂本的不理解,对于解析单个json格式的字符串,直接使⽤cJSON_Parse(str)
这样的函数,即可转换成 cJSON 格式,但是,对于⼀个完整的cJSON ⽂件,并不是简单的将⽂本读出来,转换成字符串,再进⾏调⽤。⽐如应当⽤下⾯的代码,即 获取json 对象
读取⽂件的完整内容
char* buf;
导航代码错误char*read_file(char* file_name)
{
FILE * fp =fopen(file_name,"r");
fseek(fp,0,SEEK_END);
long size =ftell(fp);
buf =(char*)malloc(size +1);
rewind(fp);
fread(buf,sizeof(char), size, fp);
buf[size]='\0';
return buf;
}
0x21 获取json对象
整体的思路就是开辟堆内存,读取⽂件,将⽂件的内容利⽤ cJSON_Parse 转换成指向 cJSON 的指针类型
cJSON *get_json_object(char* file_name)
{
FILE * fp;
long len;
char* content;
cJSON * result;
fp =fopen(file_name,"rb");
fseek(fp,0,SEEK_END);
len =ftell(fp);
fseek(fp,0,SEEK_SET);
content =(char*)malloc(len +1);
fread(content,1, len, fp);
fclose(fp);
result =cJSON_Parse(content);
free(content);
return result;
}
测试⽤例如下,注意json⽂件的格式,每组最后⼀个键值对是不需要加符号的!这很重要,不然我们的解析程序会报错。
python解析json文件
{
"people":[
{"firstName":"Tom","lastName":"Jason","email":"test@aa","height":1.77}, {"lastName":"Jerry","email":"Jerry@bb","age":8,"height":1.55},
{"email":"cccc@126","firstName":"z","lastName":"Juliet","age":36,"height":1.33}
],
"animal":{"dog":"wangcai!"}
}
0x22 解析json⽂件核⼼代码
int main(int argc,char const*argv[])
{
cJSON * root =NULL;
cJSON * item =NULL;
root =get_json_object(argv[1]);
if(!root)
{
printf("Error before: [%s]\n",cJSON_GetErrorPtr());
}
else
{
printf("有格式打印: %s\n",cJSON_Print(root));
类似爱情原唱
printf("原始⽂件: %s\n",cJSON_PrintUnformatted(root));
item =cJSON_GetObjectItem(root,"animal");
if(item)
{
printf("筛选⼀: %s\n",cJSON_Print(item));
}
item =cJSON_GetObjectItem(item,"dog");
if(item)
{
printf("筛选⼆: %s\n",cJSON_Print(item));
printf("%s:", item->string);//看⼀下cjson对象的结构体中这两个成员的意思
printf("%s\n", item->valuestring);
}
printf("打印json所有最内层键值对: %s\n");
print_json(root);
}
return0;
}
0x23 编译并运⾏
0x30 使⽤afl对cJSON库进⾏fuzz测试
合肥线上教学如果想使⽤afl-fuzz对cJSON组件进⾏安全测试,需要修改项⽬中的主⽂件 main,44 ⾏改为 45 ⾏,这是因为,afl-fuzz需要从输⼊的⽂件直接读取字符串,⽽不是直接解析json⽂件,请注意甄别。
改完代码之后,需要重写 Makefile,这⾥,项⽬已经写好了备份⽂件,直接使⽤以下命令替换即可
这时,再运⾏命令
afl-fuzz -m none -i in -o out ./main @@
成功对cJSON组件进⾏fuzz测试
0x40 总结
本⽂介绍了如何使⽤cJSON库,对json数据格式的⽂件进⾏解析,cJSON这样⼀款优秀的开源轻量级json解析库还有很多功能,⽐如创建json⽂件,限于篇幅,只是介绍了如何使⽤它进⾏数据解析。并且最后,结合afl,详细讲述利⽤源码编译的⽅式进⾏插桩,达到fuzz测试的效果。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。