zoukankan      html  css  js  c++  java
  • pwn学习日记Day2 基础知识积累

    知识杂项

    shell-storm.org的shellcode数据库
    使用pwntools库把shellcode作为输入传递给程序,尝试使用io.interactive()与程序进行交互,发现可以执行shell命令。
    shellcode:是一段可以执行特定功能的神秘代码。
    shell-storm:上还有可以执行其他功能如关机,进程炸弹,读取/etc/passwd等的shellcode。
    EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。
    EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址。
    ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
    EDX 则总是被用来放整数除法产生的余数。
    ESI/EDI分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串。
    EBP是"基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer). 在破解的时候,经常可以看见一个标准的函数起始代码:
      
      push ebp ;保存当前ebp
      mov ebp,esp ;EBP设为当前堆栈指针
      sub esp, xxx ;预留xxx字节给函数临时变量.
      ...
      
    这样一来,EBP 构成了该函数的一个框架, 在EBP上方分别是原来的EBP, 返回地址和参数. EBP下方则是临时变量. 函数返回时作 mov esp,ebp/pop ebp/ret 即可。
    ret指令用栈中的数据,修改IP的内容,从而实现近转移。
    retf指令用栈的数据,修改CS和IP的内容,从而实现远转移。
    ESP 专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。
    int setvbuf(FILE *stream, char buf, int type, unsigned size);
      参数:stream :指向流的指针 ;
      buf : 期望缓冲区的地址;
      type : 期望缓冲区的类型:
      _IOFBF(满缓冲):当缓冲区为空时,从流读入数据。或者当缓冲区满时,向流写入数 据。
      _IOLBF(行缓冲):每次从流中读入一行数据或向流中写入一行数据。
      _IONBF(无缓冲):直接从流中读入数据或直接向流中写入数据,而没有缓冲区。
      size : 缓冲区内字节的数量。
    void malloc(unsigned int num_bytes)
    malloc函数是一种分配长度为num_bytes字节的内存块的函数,可以向系统申请分配指定size个字节的内存空间。
    动态内存分配,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存。
    void
    表示未确定类型的指针。C,C++规定,void
    类型可以通过类型转换强制转换为任何其它类型的指针。
    exit(0):正常运行程序并退出程序;
    exit(1):非正常运行导致退出程序;
    return():返回函数,若在主函数中,则会退出函数并返回一值。

    shellcode原理

    每条汇编指令都对应着长短不一的一串16进制数,这些16进制数串叫做opcode。opcode是由最多6个域组成的,和汇编指令存在对应关系的机器码。或者说可以认为汇编指令是opcode的“别名”。
    易于人类阅读的汇编语言指令,如xor ecx, ecx等,实际上就是被汇编器根据opcode与汇编指令的替换规则替换成16进制数串,再与其他数据经过组合处理,最后变成01字符串被CPU识别并执行的。
    IDA之类的反汇编器也是使用替换规则将16进制串处理成汇编代码的。所以我们可以直接构造合法的16进制串组成的opcode串,即shellcode,使系统得以识别并执行,完成我们想要的功能。

    系统调用

    查阅intel开发者手册我们可以知道,int指令的功能是调用系统中断,所以int 80h就是调用128号中断。在32位的linux系统中,该中断被用于呼叫系统调用程序system_call()。
    我们知道,出于对硬件和操作系统内核的保护,应用程序的代码一般在保护模式下运行。在这个模式下我们使用的程序和写的代码是没办法访问内核空间的。但是我们显然可以通过调用read(), write()之类的函数从键盘读取输入,把输出保存在硬盘里的文件中。那么read(), write()之类的函数是怎么突破保护模式的管制,成功访问到本该由内核管理的这些硬件呢?答案就在于int 80h这个中断调用。
    不同的内核态操作通过给寄存器设置不同的值,再调用同样的 指令int 80h,就可以通知内核完成不同的功能。
    read(), write(), system()之类的需要内核“帮忙”的函数,就是围绕这条指令加上一些额外参数处理,异常处理等代码封装而成的。
    32位linux系统的内核一共提供了0~337号共计338种系统调用用以实现不同的功能。

    shellcode的变形

    在很多情况下,我们多试几个shellcode,总能找到符合能用的。但是在有些情况下,为了成功将shellcode写入被攻击的程序的内存空间中,我们需要对原有的shellcode进行修改变形以避免shellcode中混杂有x00, x0A等特殊字符,或是绕过其他限制。有时候甚至需要自己写一段shellcode。(后续Day3)

    内容来源

    i春秋月刊第六期——Linux pwn零基础入门

  • 相关阅读:
    开源大数据周刊-第29期
    rsync
    Tomcat基础教程(四)
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    python 取前10位
    python 字典统计次数
    阿里开源分布式事务Fescar demo示例
  • 原文地址:https://www.cnblogs.com/luoleqi/p/10780848.html
Copyright © 2011-2022 走看看