diff --git a/doc/5.2_pin.md b/doc/5.2_pin.md index 3bfb684..37d4c06 100644 --- a/doc/5.2_pin.md +++ b/doc/5.2_pin.md @@ -113,7 +113,7 @@ sci: ## Pin 简介 -Pin 是 Intel 公司研发的一个动态二进制插桩框架,可以在二进制程序运行过程中插入各种函数,以监控程序每一步的执行。 +Pin 是 Intel 公司研发的一个动态二进制插桩框架,可以在二进制程序运行过程中插入各种函数,以监控程序每一步的执行。[官网](https://software.intel.com/en-us/articles/pin-a-dynamic-binary-instrumentation-tool)(目前有 2.x 和 3.x 两个版本,2.x 不能在 Linux 内核 4.x 及以上版本上运行,这里我们选择 3.x) Pin 具有一下优点: - 易用 @@ -161,27 +161,27 @@ $ cd source/tools/MyPintools ``` 对于 32 位架构,使用 `TARGET=ia32`: ``` -$ make obj-ia32/mypintool.so TARGET=ia32 +[MyPintools]$ make obj-ia32/mypintool.so TARGET=ia32 ``` 对于 64 位架构,使用 `TARGET=intel64`: ``` -$ make obj-intel64/mypintool.so TARGET=intel64 +[MyPintools]$ make obj-intel64/mypintool.so TARGET=intel64 ``` 启动并插桩一个应用程序: ``` -$ ../../../pin -t obj-intel64/mypintools.so -- application +[MyPintools]$ ../../../pin -t obj-intel64/mypintools.so -- application ``` 其中 `pin` 是插桩引擎,由 Pin 的开发者提供;`pintool.so` 是插桩工具,由用户自己编写并编译。 绑定并插桩一个正在运行的程序: ``` -$ ../../../pin -t obj-intel64/mypintools.so -pid 1234 +[MyPintools]$ ../../../pin -t obj-intel64/mypintools.so -pid 1234 ``` ## Pintool 示例分析 -Pin 提供了一些 Pintool 的示例,下面我们分析一下用户手册中介绍的指令计数工具 inscount。 +Pin 提供了一些 Pintool 的示例,下面我们分析一下用户手册中介绍的指令计数工具,可以在 `source/tools/ManualExamples/inscount0.cpp` 中找到。 ```c #include #include @@ -259,6 +259,15 @@ int main(int argc, char * argv[]) - 在每条指令之前(`IPOINT_BEFORE`)执行分析函数 `docount()`,功能是对全局变量递增计数。 - 执行完成函数 `Fini()`,输出计数结果到文件。 +由于我当前使用的系统和内核版本过新,Pin 暂时还未支持,使用时需要加上 `-ifeellucky` 参数,`-o` 参数将运行结果输出到文件。运行程序: +``` +[ManualExamples]$ uname -a +Linux manjaro 4.11.5-1-ARCH #1 SMP PREEMPT Wed Jun 14 16:19:27 CEST 2017 x86_64 GNU/Linux +[ManualExamples]$ ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount0.log -- /bin/ls +[ManualExamples]$ cat inscount0.log +Count 528090 +``` + ## Pintool 编写 #### main 函数的编写 @@ -323,3 +332,93 @@ Pintool 的入口为 `main` 函数,通常需要完成下面的功能: ## Pin 在 CTF 中的应用 +由于程序具有循环、分支等结构,每次运行时执行的指令数量不一定相同,于是我们可是使用 Pin 来统计执行指令的数量,从而对程序进行分析。特别是对一些使用特殊指令集和虚拟机,或者运用了反调试等技术的程序来说,相对于静态分析去死磕,动态插桩技术是一个比较好的选择。 + +我们先举一个例子,[源码](../source/Others/5.2_pin.c)如下: +```c +#include +#include +void main() { + char pwd[] = "abc123"; + char str[128]; + int flag = 1; + scanf("%s", str); + for (int i=0; i<=strlen(pwd); i++) { + if (pwd[i]!=str[i] || str[i]=='\0'&&pwd[i]!='\0' || str[i]!='\0'&&pwd[i]=='\0') { + flag = 0; + } + } + if (flag==0) { + printf("Bad!\n"); + } else { + printf("Good!\n"); + } +} +``` +这段代码要求用户输入密码,然后逐字符进行判断。 + +使用前面分析的指令计数的 inscount0 Pintool,我们先测试下密码的长度: +``` +[ManualExamples]$ echo x | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152667 +[ManualExamples]$ echo xx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152688 +[ManualExamples]$ echo xxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152709 +[ManualExamples]$ echo xxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152730 +[ManualExamples]$ echo xxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152751 +[ManualExamples]$ echo xxxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152772 +[ManualExamples]$ echo xxxxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152779 +``` +我们输入的密码位数从 1 到 7,可以看到输入位数为 6 位或更少时,计数值之差都是 21,而输入 7 位密码时,差值仅为 7,不等于 21。于是我们知道程序密码为 6 位。接下来我们更改密码的第一位: +``` +[ManualExamples]$ echo axxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152786 +[ManualExamples]$ echo bxxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152772 +[ManualExamples]$ echo cxxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152772 +[ManualExamples]$ echo dxxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152772 +``` +很明显,程序密码第一位是 `a`,接着尝试第二位: +``` +[ManualExamples]$ echo aaxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152786 +[ManualExamples]$ echo abxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152800 +[ManualExamples]$ echo acxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152786 +[ManualExamples]$ echo adxxxx | ../../../pin -ifeellucky -t obj-intel64/inscount0.so -o inscount.out -- ~/a.out ; cat inscount.out +Bad! +Count 152786 +``` +第二位是 `b`,同时我们还可以发现,每一位正确与错误的指令计数之差均为 14。同理,我们就可以暴力破解出密码,但这种暴力破解方式大大减少了次数,提高了效率。破解脚本可查看参考资料。 + +#### 参考资料 +[A binary analysis, count me if you can](http://shell-storm.org/blog/A-binary-analysis-count-me-if-you-can/) +[pintool2](https://github.com/sebastiendamaye/pintool2) + +#### 练习 +[Baleful - picoCTF 2014](../src/5.2_baleful) +[Reverse 400 - Hack You 2014](../src/Reverse/5.2_reverse_400) +[wyvern 500 - CSAW CTF 2015](../src/Reverse/5.2_wyvern_500) +[rev100 - th3jackers CTF 2015](../src/5.2_th3jackers_100) diff --git a/src/Others/5.2_pin.c b/src/Others/5.2_pin.c new file mode 100644 index 0000000..a6a1d38 --- /dev/null +++ b/src/Others/5.2_pin.c @@ -0,0 +1,18 @@ +#include +#include +void main() { + char pwd[] = "abc123"; + char str[128]; + int flag = 1; + scanf("%s", str); + for (int i=0; i<=strlen(pwd); i++) { + if (pwd[i]!=str[i] || str[i]=='\0'&&pwd[i]!='\0' || str[i]!='\0'&&pwd[i]=='\0') { + flag = 0; + } + } + if (flag==0) { + printf("Bad!\n"); + } else { + printf("Good!\n"); + } +} diff --git a/src/Reverse/5.2_baleful b/src/Reverse/5.2_baleful new file mode 100755 index 0000000..3e8d641 Binary files /dev/null and b/src/Reverse/5.2_baleful differ diff --git a/src/Reverse/5.2_reverse_400 b/src/Reverse/5.2_reverse_400 new file mode 100755 index 0000000..fa00015 Binary files /dev/null and b/src/Reverse/5.2_reverse_400 differ diff --git a/src/Reverse/5.2_th3jackers_100 b/src/Reverse/5.2_th3jackers_100 new file mode 100755 index 0000000..f07f1db Binary files /dev/null and b/src/Reverse/5.2_th3jackers_100 differ diff --git a/src/Reverse/5.2_wyvern_500 b/src/Reverse/5.2_wyvern_500 new file mode 100755 index 0000000..15b6f25 Binary files /dev/null and b/src/Reverse/5.2_wyvern_500 differ