1625-5 王子昂 总结《2018年2月3日》 【连续第491天总结】
A. PinTools编写、win32程序的适配
B.
之前编译好了ManualExamples中的inscount,但是0、1、2的计算都很不准确,高达几百万且波动极大,所以没法通过例程的指令计数来爆破

于是只好自己参照API来修改
感觉很久没有从零开始查文档写程序啦~
官方的例程真的很充分,文档也特别详细

基础介绍

PinTools文档:
https://software.intel.com/sites/landingpage/pintool/docs/81205/Pin/html/index.html

Linux

Pin tool由int main(int argc, char * argv[])函数开始,由NMAKE编译选项编译成特定的动态链接库,如果要编译自己的动态链接库,在Nmakefile文件中把要编译的动态链接库名字加到COMMON_TOOLS=后面,使用..\nmake.bat TARGET=ia32 xxx.dll命令进行编译。

Windows

在makefile.rules中找到

TEST_TOOL_ROOTS := inscount0_win_stdout
来修改,添加目标

另外obj-ia32中的库只能对32位的程序(无论是elf还是exe使用),对于64位的程序则需要编译出obj-intel64的版本

make TARGET=ia32/intel64 可以指定目标版本

如果在程序中要使用符号,要调用PIN_InitSymbols();来初始化PIN_Init(argc, argv)

PIN tool分四种插装粒度

  • 指令级插桩(instruction instrumentatio),通过函数INS_AddInstrumentFunctio实现。

  • 轨迹级插装(trace instrumentation),通过函数TRACE_AddInstrumentFunction实现。(貌似就是基本块插装)

  • 镜像级插装(image instrumentation),使用IMG_AddInstrumentFunction函数,由于其依赖于符号信息去确定函数边界,因此必须在调用PIN_Init之前调用PIN_InitSymbols。

  • 函数级的插装(routine instrumentation),使用RTN_AddInstrumentFunction函数。函数级插装比镜像级插装更有效,因为只有镜像中的一小部分函数被执行。

其中,IMG_AddInstrumentFunction和RTN_AddInstrumentFunction需要先调用PIN_InitSymbols(),来分析出符号。在无符号的程序中,IMG_AddInstrumentFunction和RTN_AddInstrumentFunction无法分析出相应的需要插装的块。
在各种粒度的插装函数调用时,可以添加自己的处理函数在代码中,程序被加载后,在被插装的代码运行时,自己添加的函数会被调用。

INS_AddInstrumentFunctio、TRACE_AddInstrumentFunction、IMG_AddInstrumentFunction、RTN_AddInstrumentFunction指定的回调函数只有在相应的代码被分析到时才会被调用,即分析到一次只被调用一次,但程序运行过程中一般不再被调用,但INS_InsertCall之类的程序添加的函数,是在相应的代码位置添加函数,根据程序运行的情况,会被多次调用。

在INS_AddInstrumentFunctio指令级插装的代码中,只有在INS_AddInstrumentFunctio指定的函数被调用时INS指令才有效,在INS_InsertCall函数中,INS无效。

从API中可以看出
Img->Sec->Rtn->Ins,相邻的级别是可以相互转换的
例如在Img中可以通过IMG_SecHead(img)来得到首个section,再通过section遍历其中的rtn即可得到期望的主函数模块了

编写心得

image对应模块,即文件(exe/dll)
routine对应的是可识别的函数,对于无符号的exe中的用户模块,似乎通常会识别出unnamedImageEntryPoint.text两个函数,其中前者为start函数,后者为真正的main函数
instruction对应的是汇编指令,没什么好说的
trace不明白是啥来的,之后有空再试用一下

如果直接由IMG_Entry的地址和RTN_FindByAddress的越级方式获取,仅能得到一个RTN,而不是所有的RTN链表
刚开始因为没有sec的级别所以没注意,在这上卡了不少时间
start()所在的RTN中运行代码跟输入几乎无关,似乎仅在输入输出流会有几十个指令的区别

编写思路

proccount的例程中可以看出 ,用户模块的代码仅有几万,大量代码都是各种系统库的调用
那么目标是排除系统库,仅保留用户模块、即主程序的指令计数

为了尽量加快速度,我选择了在IMG级别插第一个桩,刚开始是校验地址是否为0x401000,或者模块名是否为程序名,但是一方面编写比较复杂,另一方面无法保证是否存在地址重定向,或是ASLR之类修改地址

在查找API的时候偶然发现有IMG_IsMainExecutable检查img是否为主程序,检查为我们的需求量身定做

通过它来判断截下的img是否为需要的主程序,如果不是就直接放过,是的话则进行指令插桩计数
刚开始直接通过地址取rtn,发现每次拿到的都是start,并且链接不到后一个rtn

现在想来应该是FindByAddress这个API本来拿到的就是单独一个rtn
后来发现IMG中有通过SEC来转RTN的API,这样就能取到整个RTN链了

得到RTN 以后遍历INS,插入计数的桩最后输出即可

代码

#include <fstream>
#include <iomanip>
#include <iostream>
#include <string.h>
#include "pin.H"static UINT64 icount = 0;
static string name;
ofstream outFile;VOID docount()
{icount++;
}VOID Routine(IMG img, VOID *v)
{if(IMG_IsMainExecutable(img)){SEC sec = IMG_SecHead(img);RTN rtn = (SEC_RtnHead(sec));{RTN_Open(rtn);name = RTN_Name(rtn);for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins)){INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);}RTN_Close(rtn);}}
}VOID Fini(INT32 code, VOID *v)
{outFile << name << endl << icount << endl;
}INT32 Usage()
{cout<<"Please input the win32 exe";return -1;
}int main(int argc, char * argv[])
{PIN_InitSymbols();outFile.open("inscount1_win.out", );if (PIN_Init(argc, argv)) return Usage();IMG_AddInstrumentFunction(Routine, 0);PIN_AddFiniFunction(Fini, 0
);PIN_StartProgram();return 0;
}

虽然其实相比iscount来说改动其实很小,不过对于PinTools的API理解总算是入了门 。经过修改后的程序仅仅会取main所在的一个rtn,还有一些遍历rtn、sec的代码因为在大部分程序中应该都无用所以略去了

爆破用的python2代码:

#coding=utf-8
import popen2
import stringINFILE = "test"
CMD = r"E:\ctf\pin\pin.exe -t E:\ctf\pin\source\tools\ManualExamples\obj-ia32\inscount1_win.dll -- F:\ctf\Whale\CrackMe\CrackMe.exe <" + INFILE
choices = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\]^_`{|}~"
# 重复放置0是为了保证如果0正确,有9->0这样错误到正确的变化,能正确捕获def execlCommand(command):global ffin,fout = popen2.popen2(command)fin.readline()# fin.readline()result1 = fin.readline()#获取程序自带打印信息,wrong或者correctprint(result1)if('Failed' not in result1):#输出Correct时终止循环f = 0result2 = fin.readline()#等待子进程结束,结果输出完成fin.close()def writefile(data):fi = open(INFILE,'w')fi.write(data)fi.close()def pad(data, n, padding):return data + padding * (n - len(data))flag = ''
# flag = '#7Ff@(24'
f = 1
while(f):l = 0#初始化计数器for i in choices:key = flag + i#测试字符串print(">",key)writefile(key)execlCommand(CMD)fi = open('./inscount1_win.out', 'r')# 管道写入较慢,读不到内容时继续尝试读while(1):try:# n = int(fi.read().split(' ')[1], 10)fi.readline()n = int(fi.readline())breakexcept IndexError:continuefi.close()print(n)if(n-l > 0 and l):#如果两次运行指令差别过大,说明字符正确flag += ibreakelse:l = nprint(flag)

后记

虽然总算是能跑起来了,但是由于Windows程序加载库过于多的原因,PinTools注入的速度特别慢
整个程序大概保持在每个字符花费2s的速度,对于实验程序CrackMe的47位flag来说,得到flag的每一位字符平均需要一分钟以上 总耗时还是有点夸张的

思考了一下,耗时过久有两个因素

  • 插桩参考了proccount例程,使用的是INS级的插桩,相比BBL代码块级的指令计数会慢许多。但是Img->Sec->Rtn->Ins的链中不知道该怎么引入Trace->Bbl,之后尝试一下Trace级别的插桩
  • Python逐字符+管道+PinTools三者都是比较耗时的程序,可以考虑多线程来批量运行PinTools。不过由于PinTools的原理是注入Dll,所以有点担心多线程的dll可能会彼此影响,从而得到不正确的结果。说多无益,明天跑一遍看看吧

C. 明日计划
PinTools多线程爆破尝试
Trace级理解

180203 逆向-Win下PinTools编写相关推荐

  1. win系统C++的udp通信(接收并发送)详细教程、win下inet_pton和inet_ntop无法使用解决方法

    对UDP编程0基础的可以参考这篇记录博文. 我做的是同一个程序中接收指定IP地址和端口号的信息作为输入,通过程序的算法进行处理,处理后的信息再通过另一个指定IP地址和端口号进行发送.也就是需要做两个u ...

  2. apache2.4.9 开启path_info访问_浅淡flask在win下用Apache24及mod_wsgi部署的那些坑

    浅淡flask在win下用Apache24及mod_wsgi部署的那些坑 安装部署就不指描述了,毕竟网上多得很,就说说一些坑吧. 1.中文路径问题,正常情况,Apache里配置文件用中文路径是会出错的 ...

  3. win下的输入流结束符

    在<C++ Primer>里看到说,win下的输入流结束符是Ctrl+Z,于是写了段代码来实验,发现要输入两次CTRL+Z才会退出: #include<iostream> us ...

  4. 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题

    layout: post title: 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题 key: 20180303 tags: GIT 版本管理 modify_date: 2 ...

  5. [转]Win下必备神器之Cmder

    原文地址http://www.jeffjade.com/2016/01/13/2016-01-13-windows-software-cmder/ 诚言,对于开发码字者,Mac和Linux果断要比Wi ...

  6. nginx Win下实现简单的负载均衡(2)站点共享Session

    快速目录: 一.nginx Win下实现简单的负载均衡(1)nginx搭建部署 二.nginx Win下实现简单的负载均衡(2)站点共享Session 三.nginx Win下实现简单的负载均衡(3) ...

  7. win下配置的ES中的数据在哪里可以看到?三种方式你看那种更加高大上!!!(win_Elasticsearch)

    在上一篇博客<使用logstash将Mysql中的数据导入到ElasticSearch中(详细步骤,win_Elasticsearch)>中我们提到将数据插入到es中,那我怎么知道数据是否 ...

  8. win_redis【win下安装使用redis】

    最初在linux下使用下载过redis,linux下的安装redis,但是我们在平时的java项目中普遍使用的是win下的redis,所以这里在win下安装redis. 首先重温一下redis,red ...

  9. win下svn常用操作笔记

    svn基本命令 checkout 检出 把服务器代码下载到本地一份 update 更新 把服务器上的最新代码更新到本地 commit 提交 把本地代码提交到服务器上 win下svn的客户端工具Tort ...

最新文章

  1. 一点通路由器模拟软件最新版_2019年高压电工作业考试最新版题库及答案(全部判断题)...
  2. 嵌入式linux文件系统格式,嵌入式Linux的文件系统分区及数据读写方法与流程
  3. 论文笔记之:Graph Attention Networks
  4. python控制单片机keil_PCF8591使用及Python控制
  5. Java初学者疑难杂症之:一对一和一对多的关系
  6. 大学只待成追忆,只是工作已半年,2016再见
  7. 定位于定位优化(iOS)
  8. 大数据全球战略布局全面升级
  9. Flutter高级第5篇:官方推荐的状态管理库 provider 的使用
  10. iOS: 详细的正则表达式
  11. GB28181 PTZCmd控制指令笔记
  12. 批量网刻操作系统(使用GHOST工具)
  13. 朗文3000词汇表带音标_牛津3000词汇表
  14. 注销、重启、关机快捷键命令
  15. 兜了一圈,发现想要的APK在这里有
  16. python 公众号 关注者位置_微信公众号获取用户地理位置
  17. php 照片变成卡通照片,怎么把照片做成q版卡通 照片变q版卡通人物 q版卡通头像制作...
  18. 三大运营商将重新划分4G版图
  19. 给定一个由N个非负整数构成的序列,我们来定义一下序列的中位数,如果N是奇数,在对序列排序后,中位数就是最中间的那个数,即排序后,中位数的位置为(N+1)/2,这里序列的位置从1开始。如果N是偶数,则中
  20. Matlab脚本--下载A股交易数据

热门文章

  1. 第5次作业+037+吴烨倩
  2. 数字电路10-移位寄存器和计数器
  3. 九宫格——用html+css制作一个网页
  4. 【蓝桥杯集训100题】scratch猫鼠大战 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第11题
  5. 小米手机 adbinterface_啥?消息称小米正在研发1.5亿像素镜头手机
  6. 10种相亲交友源码客户端存储,值得一看
  7. 小龙虾的做法大全 你想知道的做法全部安排上
  8. 腰椎间盘突出症的自我疗法
  9. 利用F检验来检验自变量与因变量之间的关系能否用一个线性回归模型来表示
  10. VPS SPS PPS