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. UVA 10129 Play on Words(欧拉道路)
  2. mysql什么格式转换_MySQL日期格式转换
  3. 【干货】APP产品处理加载机制和刷新机制的交互方法解析
  4. 图像处理中的dpi(Dots Per Inch)是什么单位?(图像每英寸长度内的像素点数)
  5. 如何用“区块链+稳定币”技术来提升资产证券化市场运作效率
  6. 通俗易懂,快速幂基本思想
  7. java执行exe 没捕获到输出_Java程序员注意——六种异常处理的陋习
  8. 怎么导出oracle库,【DG】怎么从Oracle备库导出数据
  9. NHibernate使用之详细图解
  10. Java 线程之间通信
  11. 3DSMAX安装未完成,某些产品无法安装的解决方法
  12. C/C++静态代码检查工具CodeChecker(一)简介
  13. c语言运算符的三大特性,逻辑运算符及其优先级,C语言逻辑运算符及其优先级详解...
  14. vdi虚拟服务器,VMware VDI部署攻略之三:VDI安装及配置
  15. matlab结构力学仿真,MATLAB在结构力学分析中应用.doc
  16. Python - 面向对象编程 - 实战(5)
  17. repo 工具使用手册
  18. 关于ABAP批次或生产订单特性值的随记
  19. 黑客技巧之教你制作一个简易的QQ炸弹
  20. 微机原理与接口技术——A.微型计算机基础(3)

热门文章

  1. C++ stack,queue(补充):deque,反向迭代器
  2. Ubuntu连接不了网络的解决方法
  3. python制作水球图
  4. 三维图形在计算机如何存储,计算机三维图形技术.pdf
  5. iBeacon销声匿迹了吗?
  6. (三)使用xftp上传文件到远程服务器
  7. 冥想心理训练有效缓解长期压力:来自头发中皮质醇浓度的检测
  8. 使用正则 去除标签, 提取HTML 纯文本
  9. MLflow基于Windows通过Docker和Minio搭建mlflow server
  10. 用Python画国旗