首页
社区
课程
招聘
[原创]初探Qiling framework
发表于: 2024-11-23 19:55 5099

[原创]初探Qiling framework

2024-11-23 19:55
5099

做完这些lab,对qiling的作用,这个framework的理解,更加的深,希望看到这里的读者可以自己去做一遍,不要纯看他人的wp,因为每道题都有着很多种解法,但是目标都是成功的hook或Hijack,Qiling还有着一些fuzz or 仿真的 example,我都会去做一遍的!同时接下来每周都有着很多考试,希望一切顺利~

Qiling是一个先进的二进制仿真框架,具有以下特点:

在qiling framework的github项目上还有几个示例demo,这里注意到了通过Qiling框架仿真模拟并对二进制程序进行hook可以更加方便的fuzz

要求在0x1337地址上写入0x1337

Qiling给出了这些Managing memory的方法

内存在被访问之前必须被映射。 map方法将连续的内存区域绑定到指定位置,并设置其访问保护位。可以提供字符串标签以便在映射信息表上轻松识别

参数:-addr - 请求的映射基地址,应该在页面粒度上;- size - 映射大小(以字节为单位),必须是页面大小; - perms - 保护位图的乘积,定义此内存范围是否可读、可写和/或可执行(可选); - info - 将字符串标签设置为映射范围以方便识别(可选)

主要也是关注前两个参数,这里显然是执行 ql.mem.map(0x1337// 4096 * 4096 , 0x1000);

参数: - addr - 要取消映射的区域基地址 - size - 区域大小(以字节为单位)

如果请求的内存范围未完全映射,则引发: QlMemoryMappedError

从部分内存范围中搜索字符串,begin和end参数均是可选的,去除则是整个内存范围

从内存中读取

写入内存

要求在uname返回系统信息时的sysname == "QilingOS" and version == "ChallengeStart"

需要通过劫持结构体

POSIX 系统调用可以被挂钩以允许用户修改其参数改变返回值完全替换其功能。系统调用可以通过其名称或编号进行挂钩,并在一个或多个阶段进行拦截: - QL_INTERCEPT.CALL - :当指定的系统调用即将被调用时,可用于完全替换系统调用功能;- QL_INTERCEPT.ENTER - :在进入系统调用之前;可用于篡改系统调用参数值 - QL_INTERCEPT.EXIT - :退出系统调用后,可能被用来篡改返回值

因此要通过ql.os.set_syscall中的QL_INTERCEPT.EXIT对返回值进行篡改

这里有个要注意的点,my_uname_ret的参数要能接受三个参数,不然会报错

这里看到qiling的一个example

Qiling都是通过一些函数,来进行hook的

Qiling的这些hook,都是一些在程序的hook,并不像正常的程序的输入输出,例如这里在退出的地方执行这个oxexit_hook函数(个人理解)

这里的第一个想法就是hook掉getrandom,控制其函数体,然后将虚拟路径/dev/urandom映射到文件对象下

以下示例将虚拟路径/dev/urandom映射到托管系统上现有的/dev/urandom文件。当模拟程序访问/dev/random时,将访问映射文件。

以下示例将虚拟路径/dev/random映射到用户定义的文件对象,以允许对交互进行更细粒度的控制。请注意,映射对象扩展了QlFsMappedObject

注意到

这里其实是一个类,然后定义了一些函数,用self来代替/dev/urandom这个对象

这里会是一个循环,我们想要的是使参数为真,而loc_E35块可以满足我们的要求,但是jl short loc_E35是显然无法满足的,因为-4和-8的位置都被置为0了是相等的,而jl是小于跳转,因此要想办法跳转到loc_E35块上

读寄存器

还有一些跨架构寄存器的获取方法

Hook

挂钩具体地址。执行指定地址时将调用已注册的回调。

挂钩所有说明。注册的回调将在每个汇编指令执行之前调用

还有一些hook,例如挂钩一段代码、挂钩中断号以调用自定义函数、拦截特定类型的指令等等

我的想法是在

这个地址执行前,在eax里写入1,这样就使得jl条件达成,就成功跳转到成功片段

这里就是让rand的返回值为0即可

这里不是系统调用的劫持,而是劫持libc函数,这里看个例子

与系统调用一样,POSIX libc 函数可以以类似的方式挂钩,从而允许用户控制其功能。

这里会有一个无限循环,movzx eax, [rbp+var_5] 先eax零扩展赋值为1,之后test al, al对al进行逻辑与的运算,结果存入ZF中,而jnz是ZF不为0则跳转,显然会有跳转,之后便是无限循环,我的想法 便是hook rax为0即可

这里有两种想法,第一种便是修改rdi,在call sleep前将rdi改为0,第二种便是hook掉sleep,直接return

这一题的target是**Unpack the struct and write at the target address.**解包结构体,然后写入目标地址

那么我的想法就是在malloc之后hook将rax返回值存入,但是我突然想到,之前我们不是刚学了如何搜索内存的吗,那么我们先通过搜索内存获得地址,然后再写入a1会不会更高端一点

第一个想法就是直接hook掉strcmp函数,或者也可以hook掉tolower函数

这里尽量hook tolower函数,不然下题就做不了啦~~~

想法就是hook掉strcmp,但是上个challenge已经成功hook掉strcmp了,因此就劫持cmdline成一个结构体,直接返回qilinglab即可

就是让esi==696C6951h && ecx==614C676Eh && eax=20202062h,就可以解决了,所以直接hook掉1195,使得这些寄存器为相应的值

如此便解决了所有的挑战

Method Description
map Map a memory region at a certain location so it become available for access
unmap Reclaim a mapped memory region
unmap_all Reclaim all mapped memory regions
map_anywhere Map a memory region in an unspecified location
protect Modify access protection bits of a mapped region (rwx)
find_free_space Find an available memory region
is_available Query whether a memory region is available
is_mapped Query whether a memory region is mapped
ql.mem.map(addr: int, size: int, perms: int = UC_PROT_ALL, info: Optional[str] = None) -> None
ql.mem.map(addr: int, size: int, perms: int = UC_PROT_ALL, info: Optional[str] = None) -> None
ql.mem.unmap(addr: int, size: int) -> None:
ql.mem.unmap(addr: int, size: int) -> None:
address = ql.mem.search(b"\xFF\xFE\xFD\xFC\xFB\xFA", begin= 0x1000, end= 0x2000)
address = ql.mem.search(b"\xFF\xFE\xFD\xFC\xFB\xFA", begin= 0x1000, end= 0x2000)
ql.mem.read(address, size)
ql.mem.read(address, size)
ql.mem.write(address, data)
ql.mem.write(address, data)
def challenge1(ql):
    ql.mem.map(0x1337//4096*4096 , 0x1000)
    ql.mem.write(0x1337, b"\x39\x05")
def challenge1(ql):
    ql.mem.map(0x1337//4096*4096 , 0x1000)
    ql.mem.write(0x1337, b"\x39\x05")
unsigned __int64 __fastcall challenge2(_BYTE *a1)
{
  unsigned int v2; // [rsp+10h] [rbp-1D0h]
  int v3; // [rsp+14h] [rbp-1CCh]
  int v4; // [rsp+18h] [rbp-1C8h]
  int v5; // [rsp+1Ch] [rbp-1C4h]
  struct utsname name; // [rsp+20h] [rbp-1C0h] BYREF
  char s[10]; // [rsp+1A6h] [rbp-3Ah] BYREF
  char v8[24]; // [rsp+1B0h] [rbp-30h] BYREF
  unsigned __int64 v9; // [rsp+1C8h] [rbp-18h]
 
  v9 = __readfsqword(0x28u);
  if ( uname(&name) )
  {
    perror("uname");
  }
  else
  {
    strcpy(s, "QilingOS");
    s[9] = 0;
    strcpy(v8, "ChallengeStart");
    v8[15] = 0;
    v2 = 0;
    v3 = 0;
    while ( v4 < strlen(s) )
    {
      if ( name.sysname[v4] == s[v4] )
        ++v2;
      ++v4;
    }
    while ( v5 < strlen(v8) )
    {
      if ( name.version[v5] == v8[v5] )
        ++v3;
      ++v5;
    }
    if ( v2 == strlen(s) && v3 == strlen(v8) && v2 > 5 )
      *a1 = 1;
  }
  return __readfsqword(0x28u) ^ v9;
}
unsigned __int64 __fastcall challenge2(_BYTE *a1)
{
  unsigned int v2; // [rsp+10h] [rbp-1D0h]
  int v3; // [rsp+14h] [rbp-1CCh]
  int v4; // [rsp+18h] [rbp-1C8h]
  int v5; // [rsp+1Ch] [rbp-1C4h]
  struct utsname name; // [rsp+20h] [rbp-1C0h] BYREF
  char s[10]; // [rsp+1A6h] [rbp-3Ah] BYREF
  char v8[24]; // [rsp+1B0h] [rbp-30h] BYREF
  unsigned __int64 v9; // [rsp+1C8h] [rbp-18h]
 
  v9 = __readfsqword(0x28u);
  if ( uname(&name) )
  {
    perror("uname");
  }
  else
  {
    strcpy(s, "QilingOS");
    s[9] = 0;
    strcpy(v8, "ChallengeStart");
    v8[15] = 0;
    v2 = 0;
    v3 = 0;
    while ( v4 < strlen(s) )
    {
      if ( name.sysname[v4] == s[v4] )
        ++v2;
      ++v4;
    }
    while ( v5 < strlen(v8) )
    {
      if ( name.version[v5] == v8[v5] )
        ++v3;
      ++v5;
    }
    if ( v2 == strlen(s) && v3 == strlen(v8) && v2 > 5 )
      *a1 = 1;
  }
  return __readfsqword(0x28u) ^ v9;
}
from qiling import Qiling
from qiling.const import QL_INTERCEPT
 
# customized system calls always use the same arguments list as the original
# ones, but with a Qiling instance on front. The Qiling instance may be used
# to interact with various subsystems, such as the memory or registers
def my_syscall_write(ql: Qiling, fd: int, buf: int, count: int) -> int:
    try:
        # read data from emulated memory
        data = ql.mem.read(buf, count)
 
        # select the emulated file object that corresponds to the requested
        # file descriptor
        fobj = ql.os.fd[fd]
 
        # write the data into the file object, if it supports write operations
        if hasattr(fobj, 'write'):
            fobj.write(data)
    except:
        ret = -1
    else:
        ret = count
 
    ql.log.info(f'my_syscall_write({fd}, {buf:#x}, {count}) = {ret}')
 
    # return a value to the caller
    return ret
 
if __name__ == "__main__":
    ql = Qiling([r'rootfs/arm_linux/bin/arm_hello'], r'rootfs/arm_linux')
 
    # the following call to 'set_syscall' sets 'my_syscall_write' to execute whenever
    # the 'write' system call is about to be called. that practically replaces the
    # existing implementation with the one in 'my_syscall_write'.
    ql.os.set_syscall('write', my_syscall_write, QL_INTERCEPT.CALL)
 
    # note that system calls may be referred to either by their name or number.
    # an equivalent alternative that replaces the write syscall by refering its number:
    #
    #ql.os.set_syscall(4, my_syscall_write)
 
    ql.run()
from qiling import Qiling
from qiling.const import QL_INTERCEPT
 
# customized system calls always use the same arguments list as the original
# ones, but with a Qiling instance on front. The Qiling instance may be used
# to interact with various subsystems, such as the memory or registers
def my_syscall_write(ql: Qiling, fd: int, buf: int, count: int) -> int:
    try:
        # read data from emulated memory
        data = ql.mem.read(buf, count)
 
        # select the emulated file object that corresponds to the requested
        # file descriptor
        fobj = ql.os.fd[fd]
 
        # write the data into the file object, if it supports write operations
        if hasattr(fobj, 'write'):
            fobj.write(data)
    except:
        ret = -1
    else:
        ret = count
 
    ql.log.info(f'my_syscall_write({fd}, {buf:#x}, {count}) = {ret}')
 
    # return a value to the caller
    return ret
 
if __name__ == "__main__":
    ql = Qiling([r'rootfs/arm_linux/bin/arm_hello'], r'rootfs/arm_linux')
 
    # the following call to 'set_syscall' sets 'my_syscall_write' to execute whenever
    # the 'write' system call is about to be called. that practically replaces the
    # existing implementation with the one in 'my_syscall_write'.
    ql.os.set_syscall('write', my_syscall_write, QL_INTERCEPT.CALL)
 
    # note that system calls may be referred to either by their name or number.
    # an equivalent alternative that replaces the write syscall by refering its number:
    #
    #ql.os.set_syscall(4, my_syscall_write)
 
    ql.run()
unsigned __int64 __fastcall challenge3(_BYTE *a1)
{
  int v2; // [rsp+10h] [rbp-60h]
  int i; // [rsp+14h] [rbp-5Ch]
  int fd; // [rsp+18h] [rbp-58h]
  char v5; // [rsp+1Fh] [rbp-51h] BYREF
  char buf[32]; // [rsp+20h] [rbp-50h] BYREF
  char v7[40]; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v8; // [rsp+68h] [rbp-8h]
 
  v8 = __readfsqword(0x28u);
  fd = open("/dev/urandom", 0);
  read(fd, buf, 0x20uLL);
  read(fd, &v5, 1uLL);
  close(fd);
  getrandom((__int64)v7, 32LL, 1LL);
  v2 = 0;
  for ( i = 0; i <= 31; ++i )
  {
    if ( buf[i] == v7[i] && buf[i] != v5 )
      ++v2;
  }
  if ( v2 == ' ' )
    *a1 = 1;
  return __readfsqword(0x28u) ^ v8;
}
unsigned __int64 __fastcall challenge3(_BYTE *a1)
{
  int v2; // [rsp+10h] [rbp-60h]
  int i; // [rsp+14h] [rbp-5Ch]
  int fd; // [rsp+18h] [rbp-58h]
  char v5; // [rsp+1Fh] [rbp-51h] BYREF
  char buf[32]; // [rsp+20h] [rbp-50h] BYREF
  char v7[40]; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v8; // [rsp+68h] [rbp-8h]
 
  v8 = __readfsqword(0x28u);
  fd = open("/dev/urandom", 0);
  read(fd, buf, 0x20uLL);
  read(fd, &v5, 1uLL);
  close(fd);
  getrandom((__int64)v7, 32LL, 1LL);
  v2 = 0;
  for ( i = 0; i <= 31; ++i )
  {
    if ( buf[i] == v7[i] && buf[i] != v5 )
      ++v2;
  }
  if ( v2 == ' ' )
    *a1 = 1;
  return __readfsqword(0x28u) ^ v8;
}
from qiling import Qiling
from qiling.os.mapper import QlFsMappedObject
 
class FakeUrandom(QlFsMappedObject):
 
    def read(self, size: int) -> bytes:
        # return a constant value upon reading
        return b"\x04"
 
    def fstat(self) -> int:
        # return -1 to let syscall fstat ignore it
        return -1
 
    def close(self) -> int:
        return 0
 
if __name__ == "__main__":
    ql = Qiling([r'rootfs/x86_linux/bin/x86_fetch_urandom'], r'rootfs/x86_linux')
 
    ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    ql.run()
from qiling import Qiling
from qiling.os.mapper import QlFsMappedObject
 
class FakeUrandom(QlFsMappedObject):
 
    def read(self, size: int) -> bytes:
        # return a constant value upon reading
        return b"\x04"
 
    def fstat(self) -> int:
        # return -1 to let syscall fstat ignore it
        return -1
 
    def close(self) -> int:
        return 0
 
if __name__ == "__main__":
    ql = Qiling([r'rootfs/x86_linux/bin/x86_fetch_urandom'], r'rootfs/x86_linux')
 
    ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    ql.run()
class FakeUrandom(QlFsMappedObject):
 
    def read(self, size: int) -> bytes:
        # return a constant value upon reading
        return b"\x04"
 
    def fstat(self) -> int:
        # return -1 to let syscall fstat ignore it
        return -1
 
    def close(self) -> int:
        return 0
class FakeUrandom(QlFsMappedObject):
 
    def read(self, size: int) -> bytes:
        # return a constant value upon reading
        return b"\x04"
 
    def fstat(self) -> int:
        # return -1 to let syscall fstat ignore it
        return -1
 
    def close(self) -> int:
        return 0
class FakeUrandom(QlFsMappedObject):
 
    def read(self, size=int) -> bytes:
        if size==0x20:
            return b"\x02"*32
        # return a constant value upon reading
        return b"\x01"
 
    def fstat(self) -> int:
        # return -1 to let syscall fstat ignore it
        return -1
 
    def close(self) -> int:
        return 0
 
def my_getrandom_func(ql, buf, count:int, flag:int) ->int:
    ql.mem.write(buf,b'\x02'*count)
    return count
 
def challenge3(ql):
    ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    ql.os.set_syscall("getrandom",my_getrandom_func,QL_INTERCEPT.CALL)
class FakeUrandom(QlFsMappedObject):
 
    def read(self, size=int) -> bytes:
        if size==0x20:
            return b"\x02"*32
        # return a constant value upon reading
        return b"\x01"
 
    def fstat(self) -> int:
        # return -1 to let syscall fstat ignore it
        return -1
 
    def close(self) -> int:
        return 0
 
def my_getrandom_func(ql, buf, count:int, flag:int) ->int:
    ql.mem.write(buf,b'\x02'*count)
    return count
 
def challenge3(ql):
    ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    ql.os.set_syscall("getrandom",my_getrandom_func,QL_INTERCEPT.CALL)
ql.arch.regs.read("EAX")
ql.arch.regs.read("EAX")
ql.arch.regs.read(UC_X86_REG_EAX)
ql.arch.regs.read(UC_X86_REG_EAX)
eax = ql.arch.regs.eax
eax = ql.arch.regs.eax
ql.arch.regs.write(UC_X86_REG_EAX, 0xFF)
ql.arch.regs.write(UC_X86_REG_EAX, 0xFF)
ql.arch.regs.eax =  0xFF
ql.arch.regs.eax =  0xFF
ql.arch.regs.arch_pc
ql.arch.regs.arch_sp  #这仅适用于 PC 和 SP。
ql.arch.regs.arch_pc = 0xFF
ql.arch.regs.arch_sp = 0xFF  #从当前架构上的 PC/SP 读取,由 ql.arch.type 定义
ql.arch.regs.arch_pc
ql.arch.regs.arch_sp  #这仅适用于 PC 和 SP。
ql.arch.regs.arch_pc = 0xFF
ql.arch.regs.arch_sp = 0xFF  #从当前架构上的 PC/SP 读取,由 ql.arch.type 定义
ql.arch.regs.register_mapping()
ql.arch.regs.register_mapping()
ql.arch.reg_bits("rax")
ql.arch.reg_bits("rax")
ql.arch.reg_bits("eax")
ql.arch.reg_bits("eax")
from qiling import Qiling
 
    def stop(ql: Qiling) -> None:
        ql.log.info('killer switch found, stopping')
        ql.emu_stop()
 
    ql = Qiling([r'examples/rootfs/x86_windows/bin/wannacry.bin'], r'examples/rootfs/x86_windows')
 
    # have 'stop' called when execution reaches 0x40819a
    ql.hook_address(stop, 0x40819a)
 
    ql.run()
from qiling import Qiling
 
    def stop(ql: Qiling) -> None:
        ql.log.info('killer switch found, stopping')
        ql.emu_stop()
 
    ql = Qiling([r'examples/rootfs/x86_windows/bin/wannacry.bin'], r'examples/rootfs/x86_windows')
 
    # have 'stop' called when execution reaches 0x40819a
    ql.hook_address(stop, 0x40819a)
 
    ql.run()
from capstone import Cs
from qiling import Qiling
from qiling.const import QL_VERBOSE
 
def simple_diassembler(ql: Qiling, address: int, size: int, md: Cs) -> None:
    buf = ql.mem.read(address, size)
 
    for insn in md.disasm(buf, address):
        ql.log.debug(f':: {insn.address:#x} : {insn.mnemonic:24s} {insn.op_str}')
 
if __name__ == "__main__":
    ql = Qiling([r'examples/rootfs/x8664_linux/bin/x8664_hello'], r'examples/rootfs/x8664_linux', verbose=QL_VERBOSE.DEBUG)
 
    # have 'simple_disassembler' called on each instruction, passing a Capstone disassembler instance bound to
    # the underlying architecture as an optional argument
    ql.hook_code(simple_diassembler, user_data=ql.arch.disassembler)
 
    ql.run()
from capstone import Cs
from qiling import Qiling
from qiling.const import QL_VERBOSE
 
def simple_diassembler(ql: Qiling, address: int, size: int, md: Cs) -> None:
    buf = ql.mem.read(address, size)
 
    for insn in md.disasm(buf, address):
        ql.log.debug(f':: {insn.address:#x} : {insn.mnemonic:24s} {insn.op_str}')
 
if __name__ == "__main__":
    ql = Qiling([r'examples/rootfs/x8664_linux/bin/x8664_hello'], r'examples/rootfs/x8664_linux', verbose=QL_VERBOSE.DEBUG)
 
    # have 'simple_disassembler' called on each instruction, passing a Capstone disassembler instance bound to
    # the underlying architecture as an optional argument
    ql.hook_code(simple_diassembler, user_data=ql.arch.disassembler)
 
    ql.run()
def write_eax_1(ql):
    ql.arch.regs.write("EAX",1)
 
def challenge4(ql):
    base_addr = ql.mem.get_lib_base(ql.path)
    ql.hook_address(write_eax_1,base_addr+0x0E43)  
def write_eax_1(ql):
    ql.arch.regs.write("EAX",1)
 
def challenge4(ql):
    base_addr = ql.mem.get_lib_base(ql.path)
    ql.hook_address(write_eax_1,base_addr+0x0E43)  
unsigned __int64 __fastcall challenge5(_BYTE *a1)
{
  unsigned int v1; // eax
  int i; // [rsp+18h] [rbp-48h]
  int j; // [rsp+1Ch] [rbp-44h]
  int v5[14]; // [rsp+20h] [rbp-40h]
  unsigned __int64 v6; // [rsp+58h] [rbp-8h]
 
  v6 = __readfsqword(0x28u);
  v1 = time(0LL);
  srand(v1);
  for ( i = 0; i <= 4; ++i )
  {
    v5[i] = 0;
    v5[i + 8] = rand();
  }
  for ( j = 0; j <= 4; ++j )
  {
    if ( v5[j] != v5[j + 8] )
    {
      *a1 = 0;
      return __readfsqword(0x28u) ^ v6;
    }
  }
  *a1 = 1;
  return __readfsqword(0x28u) ^ v6;
}
unsigned __int64 __fastcall challenge5(_BYTE *a1)
{
  unsigned int v1; // eax
  int i; // [rsp+18h] [rbp-48h]
  int j; // [rsp+1Ch] [rbp-44h]
  int v5[14]; // [rsp+20h] [rbp-40h]
  unsigned __int64 v6; // [rsp+58h] [rbp-8h]
 
  v6 = __readfsqword(0x28u);
  v1 = time(0LL);
  srand(v1);
  for ( i = 0; i <= 4; ++i )
  {
    v5[i] = 0;
    v5[i + 8] = rand();
  }
  for ( j = 0; j <= 4; ++j )
  {
    if ( v5[j] != v5[j + 8] )
    {
      *a1 = 0;
      return __readfsqword(0x28u) ^ v6;
    }
  }
  *a1 = 1;
  return __readfsqword(0x28u) ^ v6;
}
from qiling import Qiling
from qiling.const import QL_INTERCEPT
from qiling.os.const import STRING
 
# customized POSIX libc methods accept a single argument that refers to the active
# Qiling instance. The Qiling instance may be used to interact with various subsystems,
# such as the memory or registers. The customized method may or may not return a value
def my_puts(ql: Qiling):
    # Qiling offers a few conviniency methods that abstract away the access to the call
    # parameters. specifying the arguments names and types woud allow Qiling to retrieve
    # their values and parse them accordingly.
    #
    # the following call lists a single argument named 's', whose type is 'STRING'.
    # a dictionary will be created having the key 's' mapped to the null-terminated
    # string read from the memory address pointed by the first argument.
    params = ql.os.resolve_fcall_params({'s': STRING})
 
    s = params['s']
    ql.log.info(f'my_puts: got "{s}" as an argument')
 
    # emulate puts functionality
    print(s)
 
    return len(s)
 
if __name__ == "__main__":
    ql = Qiling([r'rootfs/x8664_linux/bin/x8664_hello'], r'rootfs/x8664_linux')
 
    ql.os.set_api('puts', my_puts, QL_INTERCEPT.CALL)
    ql.run()
from qiling import Qiling
from qiling.const import QL_INTERCEPT
from qiling.os.const import STRING
 
# customized POSIX libc methods accept a single argument that refers to the active
# Qiling instance. The Qiling instance may be used to interact with various subsystems,
# such as the memory or registers. The customized method may or may not return a value
def my_puts(ql: Qiling):
    # Qiling offers a few conviniency methods that abstract away the access to the call
    # parameters. specifying the arguments names and types woud allow Qiling to retrieve
    # their values and parse them accordingly.
    #
    # the following call lists a single argument named 's', whose type is 'STRING'.
    # a dictionary will be created having the key 's' mapped to the null-terminated
    # string read from the memory address pointed by the first argument.
    params = ql.os.resolve_fcall_params({'s': STRING})
 
    s = params['s']
    ql.log.info(f'my_puts: got "{s}" as an argument')
 
    # emulate puts functionality
    print(s)
 
    return len(s)
 
if __name__ == "__main__":
    ql = Qiling([r'rootfs/x8664_linux/bin/x8664_hello'], r'rootfs/x8664_linux')
 
    ql.os.set_api('puts', my_puts, QL_INTERCEPT.CALL)
    ql.run()
def rand_rets(ql ,*args):
    ql.arch.regs.write("rax",0)
 
def challenge5(ql):
    ql.os.set_api('rand', rand_rets)
    return
def rand_rets(ql ,*args):
    ql.arch.regs.write("rax",0)
 
def challenge5(ql):
    ql.os.set_api('rand', rand_rets)
    return
def write_rax_0(ql):
    ql.arch.regs.write("rax",0)
 
def challenge6(ql):
    base_addr = ql.mem.get_lib_base(ql.path)
    if base_addr is None:
        raise ValueError("base_addr is not set correctly")
    ql.hook_address(write_rax_0,base_addr+0xF16)   
def write_rax_0(ql):
    ql.arch.regs.write("rax",0)
 
def challenge6(ql):
    base_addr = ql.mem.get_lib_base(ql.path)
    if base_addr is None:
        raise ValueError("base_addr is not set correctly")
    ql.hook_address(write_rax_0,base_addr+0xF16)   
def write_rax_0(ql):
    ql.arch.regs.write("rax",0)
 
def challenge6(ql):
    base_addr = ql.mem.get_lib_base(ql.path)
    if base_addr is None:
        raise ValueError("base_addr is not set correctly")
    ql.hook_address(write_rax_0,base_addr+0xF16)   
def write_rax_0(ql):
    ql.arch.regs.write("rax",0)
 
def challenge6(ql):
    base_addr = ql.mem.get_lib_base(ql.path)
    if base_addr is None:
        raise ValueError("base_addr is not set correctly")
    ql.hook_address(write_rax_0,base_addr+0xF16)   
def write_rdi_0(ql):
    ql.arch.regs.write("rdi",0)
 
def my_sleep(ql,*args):
    return
 
def challenge7(ql):
    base_addr = ql.mem.get_lib_base(ql.path)
    if base_addr is None:
        raise ValueError("base_addr is not set correctly")
    #ql.os.set_api('sleep', my_sleep)
    ql.hook_address(write_rdi_0,base_addr+0x00F3C
def write_rdi_0(ql):
    ql.arch.regs.write("rdi",0)
 
def my_sleep(ql,*args):
    return
 
def challenge7(ql):

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 4
支持
分享
最新回复 (3)
雪    币: 1935
活跃值: (4185)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
好,感谢分享
2024-11-23 20:46
0
雪    币: 1426
活跃值: (3152)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2024-11-25 11:00
0
雪    币: 20
活跃值: (471)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
为啥现在qiling不更新了
2024-11-28 23:46
0
游客
登录 | 注册 方可回帖
返回
//