首页
论坛
专栏
课程

[原创]利用Ghidra 详细分析一道某国外ctf题

2019-5-6 20:52 1736

[原创]利用Ghidra 详细分析一道某国外ctf题

2019-5-6 20:52
1736

目录

1.ghidra 简介

不再赘述,感兴趣的可以看论坛其他相关帖子,这里给出链接
Ghidra简介与入门:
https://bbs.pediy.com/thread-250056.htm
下载:
https://bbs.pediy.com/thread-249868.htm

 

ctf地址:
https://www.root-me.org/en/Challenges/Cracking/

 

这个题目要求获得password,比较简单,旨在学习Ghidra的基本操作

2. 代码分析

1. 直接将文件拖到窗口中

2. 解析文件格式

第一次打开会解析文件系统,这里文件是elf格式

图片描述

3. 加载文件并分析

因为ghidra是java写的,所以速度会比ida的分析速度慢一些,但是很多地方额使用和ida很像,所以很容易上手

图片描述

4. 找到入口entry

图片描述

双击进入main函数

图片描述

5. 重命名

这里和ida一样可以对函数名和参数名重命名,也可以对返回类型和参数类型重新设置
我们这里重新设置一下main函数的返回类型参数类型

 

修改前:

 

图片描述
修改后:

 

图片描述

6. 分析FUN_080485a5

这里就是关键函数了
图片描述
图片描述

 

图片描述

 

##5. 查看获得密码的函数
就是这个函数获得最后的password

void FUN_0804851c(byte *param_1,char *param_2)

{
  byte *pbVar1;
  byte bVar2;
  byte *pbVar3;
  int iVar4;

  *param_1 = *param_1 ^ 0xab;
  pbVar3 = param_1 + 1;
  bVar2 = *pbVar3;
  if (bVar2 != 0) {
    iVar4 = 1;
    do {
      bVar2 = bVar2 - (char)iVar4;
      *pbVar3 = bVar2;
      pbVar1 = param_1 + iVar4 + -1;
      bVar2 = bVar2 ^ *pbVar1;
      *pbVar3 = bVar2;
      bVar2 = bVar2 + *pbVar1;
      *pbVar3 = bVar2;
      bVar2 = bVar2 ^ *pbVar1;
      *pbVar3 = bVar2;
      bVar2 = bVar2 ^ param_1[8];
      *pbVar3 = bVar2;
      if (bVar2 == 0) {
        *pbVar3 = 1;
      }
      iVar4 = iVar4 + 1;
      pbVar3 = param_1 + iVar4;
      bVar2 = param_1[iVar4];
    } while (bVar2 != 0);
  }
  bVar2 = *param_1;
  while (bVar2 != 0) {
    sprintf(param_2,"%.2x",(uint)bVar2);
    param_2 = param_2 + 2;
    param_1 = param_1 + 1;
    bVar2 = *param_1;
  }
  return;
}

3. 获得password

我们要得到这个密码,我们有两种办法

  1. 修改代码逻辑,这在Ghidra中是可行的
  2. 自己vs中写代码,得到这个代码

1. 修改代码逻辑:

我们看看需要修改哪些地方

1. ptrace检查

图片描述

 

在地址0x0804868c处,将JNS改为JMP,绕过Ptrace的检查
图片描述

 

改后:
图片描述

2. 验证

图片描述

 

如果用户提供了密码并检查提供的密码以检查它是否是有效字符或其他内容。
我们跳过这个验证

__ctype_b_loc()函数应返回指向当前语言环境中包含当前字符集中每个字符的特征的字符数组的指针。该数组应包含总共384个字符,并且可以使用任何有符号或无符号字符索引(即索引值介于128和255之间)。如果应用程序是多线程的,则该数组应该是当前线程的本地。

 

修改后:
图片描述

 

我们发现我们修改了中间的汇编指令,右边的代码也跟着发生了变化,这一点还是比较方便的

3. 修改判断逻辑

在地址0x0804861e,我们将JNZ修补为JZ
图片描述

4. 保存,运行

当我们运行这个elf文件的时候就会直接得到password

2. 写代码直接得到password

我们发现password是由FUN_0804851c这个函数得到的

 

那么我们可以直接调用这个函数就可以了

 

下面是代码

#include<windows.h>
#include<stdio.h>

void FUN_0804851c(byte *param_1, char *param_2)

{
    byte *pbVar1;
    byte bVar2;
    byte *pbVar3;
    int iVar4;

    *param_1 = *param_1 ^ 0xab;
    pbVar3 = param_1 + 1;
    bVar2 = *pbVar3;
    if (bVar2 != 0) {
        iVar4 = 1;
        do {
            bVar2 = bVar2 - (char)iVar4;
            *pbVar3 = bVar2;
            pbVar1 = param_1 + iVar4 + -1;
            bVar2 = bVar2 ^ *pbVar1;
            *pbVar3 = bVar2;
            bVar2 = bVar2 + *pbVar1;
            *pbVar3 = bVar2;
            bVar2 = bVar2 ^ *pbVar1;
            *pbVar3 = bVar2;
            bVar2 = bVar2 ^ param_1[8];
            *pbVar3 = bVar2;
            if (bVar2 == 0) {
                *pbVar3 = 1;
            }
            iVar4 = iVar4 + 1;
            pbVar3 = param_1 + iVar4;
            bVar2 = param_1[iVar4];
        } while (bVar2 != 0);
    }
    bVar2 = *param_1;
    while (bVar2 != 0) {
        sprintf_s(param_2, 100,"%.2x", (unsigned int)bVar2);
        param_2 = param_2 + 2;
        param_1 = param_1 + 1;
        bVar2 = *param_1;
    }
    return;
}


int main()
{
    char buf[4096];
    byte key[100] = "THEPASSWORDISEASYTOCRACK";
    FUN_0804851c(key, buf);
    printf("password is : %s", buf);

    system("pause");
    return 0;
}

第一次使用Ghidra就感受到了它的强大和便利,但是和ida pro相比还有很多不如的地方。。。希望Ghidra越来越完善和遍历,毕竟是开源的



[招聘]欢迎市场人员加入看雪学院团队!

上传的附件:
打赏 + 2.00
打赏次数 1 金额 + 2.00
收起 
赞赏  junkboy   +2.00 2019/05/07
最新回复 (6)
junkboy 2019-5-7 00:02
2
0
支持
21花生 2 2019-5-7 08:13
3
0
junkboy 支持
多谢
21花生 2 2019-5-7 08:13
4
0
junkboy 支持
我是不是放错板块了
killpy 2 2019-5-8 00:24
5
0
666
21花生 2 2019-5-15 23:38
6
0
感觉放错板块了  不知道能不能换个板块
罗小墨 2019-5-20 08:25
7
0
感觉还是没有ida方便和快捷,个人意见
游客
登录 | 注册 方可回帖
返回