Keen面试回顾

Keen的二面结束了,这篇博客主要是写一些在面试中被问到的问题,并且及时总结自己不足的地方。二面面试官水平非常高,一看就是行业内顶尖、且具有多年经验的大佬。面试中提问的问题特别的仔细,虽然都是基础,但是问题非常的细,平常工作的时候忽略了这些问题。

由于最近还需要准备其他面试,所以需要慢慢更新这篇文章。

CanaryFS

面试中问到了Canary的问题,其中闻到了Canary保存的位置,我印象中Canary是被保存到了寄存器FS[0x28]处,实际上我记得是对的,但是问题是我不清楚FS[0x28]到底指向了哪里。

后面我找了一个二进制程序调了一下,结果可以看下面的调试内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pwndbg> canary
canary : 0xcd8facfa4db1b200
pwndbg> i r
rax 0x555555556230 93824992240176
......;some registers' info.
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
fs_base 0x7ffff7f87740 140737353643840
gs_base 0x0 0
pwndbg> search -t qword "0xcd8facfa4db1b200"
Searching for value: b'\x00\xb2\xb1M\xfa\xac\x8f\xcd'
[anon_7ffff7f87] 0x7ffff7f87768 0xcd8facfa4db1b200
[stack] 0x7fffffffd948 0xcd8facfa4db1b200
[stack] 0x7fffffffd988 0xcd8facfa4db1b200
[stack] 0x7fffffffdce8 0xcd8facfa4db1b200
pwndbg>

可以看到,fs寄存器指向虚拟内存的较高处,实际上就比程序的动态链接库映射的虚拟内存低一点点,canary就保存在这里。

fs_base的值为0x7ffff7f87740,加上0x28的偏移,就是0x7ffff7f87768,用search -t正好可以查找到这个canary的值。

0x7ffff7f87000 0x7ffff7f8a000 rw-p 3000 0 [anon_7ffff7f87]

可以看到这个段具有写权限,所以实际上可以通过修改这个canary来对canary进行控制。

虽然这个问题如果让我上手去查的话可以一分钟左右的时间就可以搞定,但毕竟这种基础知识涉及到对程序虚拟内存的了解程度。还需了解透彻。

AntiDebug

  • ptrace

参考文章文章 - Linux逆向之调试&反调试 - 先知社区

ptrace是Linux的系统调用,专门用来调试的。GDB 就是基于ptrace编写而成的调试器,ptrace是一个Linux提供的用于调试的系统调用。

函数原型

1
2
3
4
5
6
NAME 
ptrace - process trace
SYNOPSIS
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid,
void *addr, void *data);

ptrace系统调用提供了一种方法来让父进程可以观察和控制其它进程的执行,检查和改变其核心映像以及寄存器。 主要用来实现断点调试和系统调用跟踪。

  • ptrace如何实现反调试?

ptrace有个规定是,每个进程只能被PTRACE_TRACEME一次。

如果在进程运行的开头直接运行一次PTRACE_TRACEME,那么gdb挂钩调试的时候再次PTRACE_TRACEME就会失效。

1
2
3
4
5
6
7
8
9
10
11
12
#include <sys/ptrace.h>
#include <stdio.h>
int main()
{
if (ptrace(PTRACE_TRACEME, 0, 0, 0) ==-1 )
{
printf("don't trace me:(\n");
return 1;
}
printf("no one trace me:)\n");
return 0;
}

如何绕过?

  1. 打patch。
  2. hook技术,把ptrace函数给替换成自定义的ptrace函数。
  3. gdb catch syscall ptrace。发生ptrace调用的时候停下,因此在第二次停住的时候set $rax=0,从而绕过程序中ptrace(PTRACE_TRACEME, 0, 0, 0) ==-1的判断。
  • 进阶方法,父子进程反调试

父进程起动子进程,让子进程与父进程之间有强烈交互关系,这样如果gdb代替父进程去attach子进程,那么子进程与父进程就会断开交互,此时程序逻辑就会出错。

如何绕过?

逆向发现父子进程直接的互动、patch掉。

还有一些反调试方法:

设置时间间隔(alarm)、检测/proc/self/status、/proc/self/cmdline、忽略int3异常信号等。

C++智能指针与内存检测

竞态漏洞

如果Fuzzer在Fuzz的过程中遇到了一个竞态条件产生的crash,如何复现?

函数返回值是Struct的汇编、全局变量的引用

经过测试,如果函数返回值是一个Struct结构体,那么返回的是指向结构体的指针。如果结构体是局部变量,那么它将存储在栈上。

此外,一般来说全局变量的引用都是cs:偏移。在gdb中看是[rip + offset]。这是因为实际上代码段和数据段之间的偏移是固定的。全局变量可以根据rip的位置来确定。