首页
社区
课程
招聘
[原创] Pintools 之 Shadow Stack 编写
发表于: 2020-9-6 16:21 6467

[原创] Pintools 之 Shadow Stack 编写

2020-9-6 16:21
6467

本文是对加州大学滨州分校cs260实验二的作答.shadow stack是一种防护机制,保护函数返回值地址被覆写.阅读本篇文章前要求对Intel Pin有一定的了解.

思路

根据实验指导,初步的shadow stack 运行原理如下:

代码

测试

思路

版本一代码只适合检测单线程情况下的覆写,多线程情况下会更加复杂的入栈和出栈操作.
如: thread1 : call fun1, thread2 : call fun2. 分别将thread1和thread2的返回值地址ret_Address1和ret_Address2依次压入stack中。此时栈顶为ret_Address2,但若线程切换至thread1, 并执行ret指令,就会出现不匹配的情况,但此时并不是将返回值地址覆写的情况. 为此,我们需要为每个线程设置一个shadow stack, 其余操作和版本一相同,部分代码做了优化.

代码

请使用最新的Intel Pin进行实验,否则会出现各种问题.

wikipedia
cs260
intel pin

 
 
// example01.c
#include <stdio.h>
#include <string.h>

int IsPasswordOkay(void)
{
  char Password[12];
  gets(Password);

  if (!strcmp(Password, "goodpass"))
    return 1;

  return 0;
}

int main(void)
{
  int PwStatus;

  puts("Enter password:");
  PwStatus = IsPasswordOkay();
  if (PwStatus == 0) {
    puts("Access denied");
    return -1;
  }
  puts("Access granted");
  return 0;
}
// 版本一
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <cstdlib>
#include <vector>
#include "pin.H"

using std::cerr;
using std::ofstream;
using std::ios;
using std::string;
using std::endl;
using std::hex;
using std::cout;

std::vector<unsigned int> stack;

VOID call_ins_call(ADDRINT ip, UINT32 size){
    // 入栈
    UINT32 next_eip = ip + size;
    stack.push_back(next_eip);
}

VOID ret_ins_call(CONTEXT * ctxt){
    VOID * current_esp = (VOID *)PIN_GetContextReg(ctxt, REG_STACK_PTR);
    UINT32 current_eip = (UINT32)(*(int *)current_esp);
    if(stack.size() > 0){
        // 出栈并比较
        UINT32 original_ret_value = (UINT32)stack.back();
        stack.pop_back();
        if(original_ret_value != current_eip){

            cout << "control flow jacking is happending" << endl;
            exit(1);
        }
    } else {
        cout << "stack is empty" << endl;
    }

}

VOID Trace(TRACE trace, VOID *v)
{
    // Visit every basic block  in the trace
    for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
    {
        for(INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)){
            // 是call 指令
            if(INS_IsCall(ins)){
                UINT32 size = INS_Size(ins);
                INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)call_ins_call, 
                    IARG_INST_PTR, 
                    IARG_UINT32, size,
                    IARG_END);
            }
            // 是 ret指令
            if(INS_IsRet(ins)){
                INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)ret_ins_call, IARG_CONTEXT, IARG_END);
            }    
        }

    }
}


// This function is called when the application exits
VOID Fini(INT32 code, VOID *v)
{
    cout << "Over" << endl;
}

/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */

INT32 Usage()
{
    cerr << "This tool is used to detect control flow jacking" << endl;
    return -1;
}

/* ===================================================================== */
/* Main                                                                  */
/* ===================================================================== */

int main(int argc, char * argv[])
{
    // Initialize symbol process
    PIN_InitSymbols();
    // Initialize pin
    if (PIN_Init(argc, argv)) {
        return Usage();
    }

    // 注册Trace粒度回调函数
    TRACE_AddInstrumentFunction(Trace, 0);

    // Register Fini to be called when the application exits
    PIN_AddFiniFunction(Fini, 0);

    // Start the program, never returns
    PIN_StartProgram();

    return 0;
}
# 编译 example01
gcc -g -fno-stack-protector  -z execstack -o example01 example01.c

# 编译pin tools 之 shadow stack, 将上述代码替换source/tools/ManualExamples/inscount0.cpp中的内容
make


# 测试

# 正常情况
path/pin -t ./inscount0.so -- ./example01
Enter password:
11111111
Access denied

# 覆写情况
Enter password:
111111111111111111111111111111111111                    
control flow jacking is happending

# core dump情况
Enter password:
11111111111111
Over
Segmentation fault (core dumped)

# 说明
# 只有覆盖了返回值地址才会被检测出来,如果长度不够,指挥core dump.

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2020-9-6 16:23 被baolongshou编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//