基本概念字典是另一种可变容器模型,且可存储任意类型对象。
字典的每个键值 key=>value 对用冒号 : 分割,每个对之间用逗号(,)分割,整个字典包括在花括号 {} 中 ,格式如下所示:
1d = {key1 : value1, key2 : value2, key3 : value3 }
注意:dict 作为 Python 的关键字和内置函数,变量名不建议命名为 dict。
键必须是唯一的,但值则不必。
值可以取任何数据类型,但键必须是不可变的,如字符串,数字。
创建字典12#一个简单的字典实例:tinydict = {'name': 'xxx', 'likes': 123, 'url': 'www.baidu.com'}
也可以如此创建字典
12tinydict1 = { 'abc': 456 }tinydict2 = { 'abc': 123, 9 ...
[HNCTF 2022 WEEK4]ezheapNSS
来看题目
123456789101112131415161718192021222324252627282930313233343536373839404142int __fastcall __noreturn main(int argc, const char **argv, const char **envp){ int v3; // [rsp+Ch] [rbp-4h] init_env(argc, argv, envp); puts("Easy Note."); while ( 1 ) { while ( 1 ) { menu(); v3 = getnum(); if ( v3 != 4 ) break; edit(); } if ( v3 > 4 ) {LABEL_13: puts("Invalid!"); } ...
变量在什么情况共用一块内存区域1. 不可变对象的引用复用Python 为了提高内存使用效率,对于一些不可变对象(如整数、字符串、元组等)会进行引用复用。当多个变量被赋值为相同的不可变对象时,它们通常会引用内存中的同一个对象。
整数在 Python 中,对于小整数(通常范围是 -5 到 256),Python 会缓存这些整数对象,多个变量赋值为相同的小整数时会共用内存。
字符串对于一些短字符串和符合标识符规则的字符串,Python 也会复用内存。
2. 直接赋值当使用直接赋值语句将一个变量赋值给另一个变量时,两个变量会引用同一个对象,即共用内存区域。这种情况对于可变对象(如列表、字典、集合等)和不可变对象都适用。
3. 函数参数传递在 Python 中,函数参数传递是通过对象引用进行的。当将一个对象作为参数传递给函数时,函数内部的参数变量和外部的变量会引用同一个对象。
4. 浅拷贝的部分情况对于包含可变对象的嵌套结构,浅拷贝只会复制最外层对象,而内部的可变对象仍然是引用关系,即共用内存区域。
close(1)关闭标准输出流解决方法 exec 1 > &0在Linux中
一切都可以作为文件,文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符。程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。 如果此时去打开一个新的文件,它的文件描述符会是3。
而标准输入输出的指向是默认的,我们也可以去修改他的指向,也就是重定位文件描述符。 例如,可以用exec 1>myoutput把标准输出重定向到myoutput文件中,也可以用exec 0<myinput把标准输入重定向到myinput文件中,而且,文件名字可以用&+文件描述符来代替。
close(1);close(2);便是关闭了 标准输出和 标准错误输出
但我们就可以使用重定位文件描述符的办法,将标准输出重定位到标准输入上来达到返回shell的目的(因为默认打开一个终端后,0,1,2都指向的是当前终端,所以该语句相当于重启 ...
堆1.堆是由操作系统内核或者堆管理器动态分配的
2.只有在程序中需要时才会分配
3.在CTF的pwn程序中,栈是程序加载进内存后就会出现,而堆需要malloc,alloc,realoc函数分配内存后才会出现。
Windows和Linux下的堆分配,管理方式都不同,
堆在虚拟内存中的位置
128M
123456789101112131415161718*用户空间*(独立).reserve(预留) //0x00000000 ----- 0x0848000.text(代码段).data //数据段.bss(默认为0) //数据段heap(堆)libc.so(共享库)stack(栈)argv|----命令行参数envp|---->环境变量*内核空间*(共享)ZONE_DMA(16M)ZONE_NORMAL(892M)ZONE_HIGHMEN(128M)
堆的生长方向是从低地址向高地址生长的,而栈是从高地址向低地址生长的
生长方向不同的原因
内存利用效率:堆和栈的生长方向不同可以让空闲的内存最大程度地被使用。如果栈的生长方向也是向上增长,那么栈空 ...
[CISCN 2019东北]PWN2123456789101112131415161718192021222324252627282930313233343536373839int __fastcall main(int argc, const char **argv, const char **envp){ int v4; // [rsp+Ch] [rbp-4h] BYREF init(argc, argv, envp); puts("EEEEEEE hh iii "); puts("EE mm mm mmmm aa aa cccc hh nn nnn eee "); puts("EEEEE mmm mm mm aa aaa cc hhhhhh iii nnn nn ee e "); puts("EE mmm mm ...
文件操作文件操作的实现将帮助我们把数据存储到文件中,既硬盘上的文件,如我们所熟知的txt格式,或其他各种后缀的文件,避免程序结束后数据丢失,实现存储数据的功能,甚至充当“数据库”的功能。
操作文件的步骤简单来说分为三步
第一步:打开文件
第二步:读写文件
第三步:关闭文件
第一步可以通过fopen函数来实现,这一步作用主要是建立程序和文件的关系,获取文件在内存中的文件指针,方便后面两步。
第二步读写文件分为fprintf、fscanf或者fwrite、fread或者fputs、getss等多组函数来实现。
每组函数都分别是写和读文件。就像我们熟知的printf和scanf这组输入输出文件一样,这不过这里的读写不是向屏幕,而是向文件。
第三步关闭文件则需要fclose函数实现。
这一步则是切断文件指针和文件的关联,避免误操作。如果未关闭文件就对文件进行读写删除等操作,就是出现类似“正在被使用,无法修改”的提示
在C语言中,对文件操作之前,首先需要打开文件,使用的函数是fopen函数,它的作用是打开文件,获取该文件的文件指针,方便后续操作。函数原型为:
1FILE *fopen(const ...
1.什么是结构体字符指针也可以指向一个字符串,可以用字符串常量对字符指针进行初始化。例如:
char *str = “www.baidu.com“ ;
这是对字符指针进行初始化。此时,字符指针指向一个字符串常量的首地址。
而结构体与数组类似,都是由若干分量组成的,与数组不同的是,结构体的成员可以是不同类型,可以通过成员名来访问结构体的元素(数组一般通过下标)。
结构体的定义说明了它的组成成员,以及每个成员的数据类型。定义一般形式如下:
1234567struct //结构类型名 { 数据类型 成员名 1; 数据类型 成员名 2; ...... 数据类型 成员名 n; };
结构的定义说明了变量在结构中的存在格式,要使用该结构就必须说明结构类型的变量
我们可以将变量student1说明为address类型的结构变量
例如:
1struct address student1;
2.怎么使用结构体虽然,结构体作为若干成员的集合是一个整体,但在使用结构时,不仅要对结构的整体进行操作,还经常要访问结构中的每一个成员。在程序中使用结 ...
[GDOUCTF 2023]EASY PWNshift+F12字符串检索
发现flag.txt
1234567int __fastcall main(int argc, const char **argv, const char **envp){ setbuf(_bss_start, 0LL); puts("If I gaslight you enough, you won't be able to guess my password! :)"); check(); return 0;}
进入check函数
12345678910111213141516171819202122232425262728293031323334353637int check(){ int result; // eax char buf[10]; // [rsp+7h] [rbp-29h] BYREF char s1[15]; // [rsp+11h] [rbp-1Fh] BYREF ssize_t v3; // [rsp+20h ...
什么是栈迁移?在了解栈迁移之前,让我们先来了解一下什么是栈溢出
栈是C语言中一种重要的数据结构,在C语言中,函数调用时会利用栈来管理局部变量、返回地址等信息。但是实际上,计算机程序的运行都依赖于函数调用栈。同时,栈也常用于一些算法的实现,如果对栈结构不了解,请移步我之前的博客。
栈溢出是指在程序运行过程中,栈帧被填满,栈空间不足以接收多出来的数据,导致这部分数据溢出覆盖了栈空间原有的地址
例如get()函数,就是常见的栈溢出点
因此,栈溢出能使我们覆盖栈上某些区域的值,甚至是当前函数的返回地址ret,一旦ret覆盖为某个奇怪的值,例如0xabcdef,当函数调用结束恢复调用现场时,程序会跳转到内存中的0xabcdef处。此刻,内核会立刻告诉我们“SLGSEV”,即常见的段错误
问题来了,如果这个值是一个合法地址呢,如果它是程序中某个函数甚至是shellcode的地址呢,因此,一旦缓冲区变量可以被恶意用户控制,而且栈空间足够大,程序原有的执行流很可能会被破坏,使得攻击者提权拿到shell
在完成栈溢出攻击的过程中,有一个充分条件是(栈上有足够的地方让攻击者进行布局)。通常的函数栈剩余空间 ...