逆向攻防世界CTF系列41-EASYHOOK

news2024/11/19 5:40:05

逆向攻防世界CTF系列41-EASYHOOK

看题目是一个Hook类型的,第一次接触,虽然学过相关理论,可以看我的文章

Hook入门(逆向)-CSDN博客

题解参考:https://www.cnblogs.com/c10udlnk/p/14214057.html和攻防世界逆向高手题之EASYHOOK-CSDN博客

int __cdecl main(int argc, const char **argv, const char **envp){
  HANDLE FileA; // eax
  DWORD NumberOfBytesWritten; // [esp+4h] [ebp-24h] BYREF
  char Buffer[32]; // [esp+8h] [ebp-20h] BYREF

  sub_401370(aPleaseInputFla);
  scanf("%31s", Buffer);
  if ( strlen(Buffer) == 19 ){
    sub_401220();
    // 创建文件 (文件名,表示文件以写入模式打开,文件不允许共享访问(即独占模式),不设置安全属性,创建新文件,文件属性设置为普通		文件,模板文件)
    FileA = CreateFileA(FileName, 0x40000000u, 0, 0, 2u, 0x80u, 0);
    // (文件句柄:表示目标文件,写入的数据,表示写入的字节数,写入的实际字节数存储位置,同步写入[不使用异步操作])
    WriteFile(FileA, Buffer, 0x13u, &NumberOfBytesWritten, 0);
    sub_401240(Buffer, &NumberOfBytesWritten);// 验证函数
    if ( NumberOfBytesWritten == 1 )
      sub_401370(aRightFlagIsYou);
    else
      sub_401370(aWrong);
    system(Command);
    return 0;
  }
  else{
    sub_401370(aWrong);
    system(Command);
    return 0;
  }
}

跟进401240

int __cdecl sub_401240(const char *a1, _DWORD *a2)
{
  int result; // eax
  unsigned int v3; // kr04_4
  char v4[24]; // [esp+Ch] [ebp-18h] BYREF

  result = 0;
  strcpy(v4, "This_is_not_the_flag");
  v3 = strlen(a1) + 1;
  if ( (int)(v3 - 1) > 0 )
  {
    while ( v4[a1 - v4 + result] == v4[result] )
    {
      if ( ++result >= (int)(v3 - 1) )
      {
        if ( result == 21 )
        {
          result = (int)a2;
          *a2 = 1;
        }
        return result;
      }
    }
  }
  return result;
}

v4[a1 - v4 + result] == v4[result]??,完全不通啊

还看了汇编源码,没看懂 0.0

看下sub_401220先

int sub_401220()
{
  HMODULE LibraryA; // eax
  DWORD CurrentProcessId; // eax
  // 1. 获取当前进程句柄
  // GetCurrentProcessId:获取当前进程的进程 ID。
  // OpenProcess:使用当前进程 ID,以 0x1F0FFFu 权限打开当前进程
  CurrentProcessId = GetCurrentProcessId();
  hProcess = OpenProcess(0x1F0FFFu, 0, CurrentProcessId);
  // 2. 加载目标库和获取函数地址
  // 动态加载一个DLL文件。
  // 成功后返回该库的模块句柄 LibraryA。
  // GetProcAddress:从 LibraryA 中获取目标函数(ProcName)的地址,存储到 WriteFile_0。函数签名定义为 BOOL WriteFile(...)。
  LibraryA = LoadLibraryA(LibFileName);
  WriteFile_0 = (BOOL (__stdcall *)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED))GetProcAddress(LibraryA, ProcName);
  // 3. 检查函数是否获取成功
  lpAddress = WriteFile_0;
  if ( !WriteFile_0 )
    return sub_401370((int)aApi);
  // 4. 保存原函数的前几字节
  // 将 WriteFile_0 的前 5 字节保存到 unk_40C9B4 中。_DWORD:前 4 字节。_BYTE:第 5 字节。
  unk_40C9B4 = *(_DWORD *)lpAddress;
  *((_BYTE *)&unk_40C9B4 + 4) = *((_BYTE *)lpAddress + 4);
  // 5. 计算跳转偏移量
  // byte_40C9BC = -23:一个额外的字节赋值(可能和跳转相关)
  // 计算一个偏移量,用于跳转到 sub_401080。
  byte_40C9BC = -23;
  dword_40C9BD = (char *)sub_401080 - (char *)lpAddress - 5;
  return sub_4010D0();
}

这里犯了个错,不是-23而是0XE9,是JMP的机器码指令

image-20241118215218470

byte_40C9BC和dword_40C9BD是相邻的,连起来就是 jmp xxxx四个字节

偏移地址=目标地址-当前地址-5(jmp和其后四位地址共占5个字节)。所以前面直接用E9,这里直接用偏移地址就省去编译生成机器码那一步。

看看sub_4010D0()

BOOL sub_4010D0()
{
  DWORD v1; // [esp+4h] [ebp-8h] BYREF
  DWORD flOldProtect; // [esp+8h] [ebp-4h] BYREF

  v1 = 0;
  // hProcess:目标进程的句柄。
  // lpAddress:目标内存地址
  // 5u:操作的字节数。
  // 4u:新的内存保护属性(可读写)。
  // &flOldProtect:存储原始内存保护属性。
  VirtualProtectEx(hProcess, lpAddress, 5u, 4u, &flOldProtect);
  //  byte_40C9BC 的内容写入目标进程中 lpAddress 开始的 5 字节区域
  WriteProcessMemory(hProcess, lpAddress, &byte_40C9BC, 5u, 0);
  return VirtualProtectEx(hProcess, lpAddress, 5u, flOldProtect, &v1);
}

jmp那里会跳转到目标地址sub_401080处,双击跟踪该函数:

int __stdcall sub_401080(
        HANDLE hFile,
        LPCVOID lpBuffer,
        DWORD nNumberOfBytesToWrite,
        LPDWORD lpNumberOfBytesWritten,
        LPOVERLAPPED lpOverlapped)
{
  int v5; // ebx

  v5 = sub_401000(lpBuffer, nNumberOfBytesToWrite);
  sub_401140();
  WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
  if ( v5 )
    *lpNumberOfBytesWritten = 1;
     // 这里才是真正的校验结果的验证
  return 0;
}

sub_401000();才是真正的加密函数

BOOL sub_401140()
{
  DWORD v1; // [esp+4h] [ebp-8h] BYREF
  DWORD flOldProtect; // [esp+8h] [ebp-4h] BYREF

  v1 = 0;
  VirtualProtectEx(hProcess, lpAddress, 5u, 4u, &flOldProtect);
  WriteProcessMemory(hProcess, lpAddress, &unk_40C9B4, 5u, 0);
  return VirtualProtectEx(hProcess, lpAddress, 5u, flOldProtect, &v1);
}
int __cdecl sub_401000(int a1, int a2)
{
  char i; // al
  char v3; // bl
  char v4; // cl
  int v5; // eax

  for ( i = 0; i < a2; ++i ){
    if ( i == 18 ){
      *(_BYTE *)(a1 + 18) ^= 0x13u;
    }
    else{
      if ( i % 2 )
        v3 = *(_BYTE *)(i + a1) - i;
      else
        v3 = *(_BYTE *)(i + a1 + 2);
      *(_BYTE *)(i + a1) = i ^ v3;
    }
  }
  v4 = 0;
  if ( a2 <= 0 )
    return 1;
  v5 = 0;
  while ( byte_40A030[v5] == *(_BYTE *)(v5 + a1) ){
    v5 = ++v4;
    if ( v4 >= a2 ) return 1;
  }
  return 0;
}

解密代码


enc = [
  0x61, 0x6A, 0x79, 0x67, 0x6B, 0x46, 0x6D, 0x2E, 0x7F, 0x5F,
  0x7E, 0x2D, 0x53, 0x56, 0x7B, 0x38, 0x6D, 0x4C, 0x6E
]

flag=list("-------------------")

for i in range(len(enc)):
    if i == 18:
        enc[i] ^= 0x13
    else:
        v3 = enc[i] ^ i
        if i % 2 == 1:
            flag[i] = chr(v3 + i)
        else:
            flag[i + 2] = chr(v3)

for i in range(len(enc)):
    print(flag[i],end='')

引用别人博客的一句话:

现在程序流程就很明朗了,粗略来看程序流程是CreateFileA->(lpAddress里存的指令)WriteFile->sub_401240,但是在经过sub_401220()的处理以后,变成了CreateFileA->(lpAddress里存的指令)sub_401080->sub_401240。

sub_401240中即使不符合也不会给NumberOfBytesWritten置成0

nd=‘’)


> 引用别人博客的一句话:

> > 现在程序流程就很明朗了,粗略来看程序流程是CreateFileA->(lpAddress里存的指令)WriteFile->sub_401240,但是在经过sub_401220()的处理以后,变成了CreateFileA->(lpAddress里存的指令)sub_401080->sub_401240。

sub_401240中即使不符合也不会给NumberOfBytesWritten置成0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2243173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络】HTTP 协议

目录 基本概念基于 HTTP 的系统组成HTTP 的基本性质 HTTP 请求头 & 响应头HTTP 的请求方法HTTP 的返回码HTTP 的 CookieHTTP 缓存 Cache-Control会话HTTP/1.x 的连接管理 基本概念 HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一…

执行flink sql连接clickhouse库

手把手教学&#xff0c;flink connector打通clickhouse大数据库&#xff0c;通过下发flink sql&#xff0c;来使用ck。 组件版本jdk1.8flink1.17.2clickhouse23.12.2.59 1.背景 flink官方不支持clickhouse连接器&#xff0c;工作中难免会用到。 2.方案 利用GitHub大佬提供…

笔记|M芯片MAC (arm64) docker上使用 export / import / commit 构建amd64镜像

很简单的起因&#xff0c;我的东西最终需要跑在amd64上&#xff0c;但是因为mac的架构师arm64&#xff0c;所以直接构建好的代码是没办法跨平台运行的。直接在arm64上pull下来的docker镜像也都是arm64架构。 检查镜像架构&#xff1a; docker inspect 8135f475e221 | grep Arc…

免费送源码:Java+Springboot+MySQL Springboot多租户博客网站的设计 计算机毕业设计原创定制

Springboot多租户博客网站的设计 摘 要 博客网站是当今网络的热点&#xff0c;博客技术的出现使得每个人可以零成本、零维护地创建自己的网络媒体&#xff0c;Blog站点所形成的网状结构促成了不同于以往社区的Blog文化&#xff0c;Blog技术缔造了“博客”文化。本文课题研究的“…

代码随想录第46期 单调栈

这道题主要是单调栈的简单应用 class Solution { public:vector<int> dailyTemperatures(vector<int>& T) {vector<int> result(T.size(),0);stack<int> st;st.push(0);for(int i1;i<T.size();i){if(T[i]<T[st.top()]){st.push(i);}else{wh…

【Three.js基础学习】24. shader patterns

前言 课程回顾: ShaderMaterial 这里用的是着色器材质 所以顶点和片段着色器就不需要像原始着色器那样添加需要的属性 然后写 片段着色器需要属性 &#xff1a; 顶点 属性 -》变化 -》 片段中 顶点中的属性不需要声明 只需要声明传送的变量 例如 varying vec vUv; vUv uv; 补充…

力扣整理版七:二叉树(待更新)

满二叉树&#xff1a;如果一棵二叉树只有度为0的结点和度为2的结点&#xff0c;并且度为0的结点在同一层上&#xff0c;则这棵二叉树为满二叉树。深度为k&#xff0c;有2^k-1个节点的二叉树。 完全二叉树&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&am…

173. 二叉搜索树迭代器【 力扣(LeetCode) 】

文章目录 零、原题链接一、题目描述二、测试用例三、解题思路四、参考代码 零、原题链接 173. 二叉搜索树迭代器 一、题目描述 实现一个二叉搜索树迭代器类BSTIterator &#xff0c;表示一个按中序遍历二叉搜索树&#xff08;BST&#xff09;的迭代器&#xff1a; BSTIterato…

自动驾驶系列—深入解析自动驾驶车联网技术及其应用场景

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

STL序列式容器之list

相较于vector的连续性空间&#xff0c;list相对比较复杂&#xff1b;list内部使用了双向环形链表的方式对数据进行存储&#xff1b;list在增加元素时&#xff0c;采用了精准的方式分配一片空间对数据及附加指针等信息进行存储&#xff1b; list节点定义如下 template<clas…

Element-ui Select选择器自定义搜索方法

效果图 具体实现 <template><div class"home"><el-selectref"currencySelect"v-model"currency"filterable:spellcheck"false"placeholder"请选择":filter-method"handleCurrencyFilter"change&q…

Linux debian系统安装ClamTk开源图形用户界面(GUI)杀毒软件

一、ClamTk简介 ClamTk 是一个基于 ClamAV 的开源图形用户界面&#xff08;GUI&#xff09;杀毒软件。它使用 GTK2-Perl 脚本构建而成&#xff0c;支持32位与64位操作系统。ClamTk 提供了一个直观的用户界面&#xff0c;使得用户无需深入了解命令行即可完成大部分操作。它具备…

MIT6.5840 Lab 1: MapReduce(6.824)

结果 介绍 在本实验中&#xff0c;您将构建一个MapReduce系统。您将实现一个调用应用程序Map和Reduce函数并处理文件读写的工作进程&#xff0c;以及一个将任务分发给工作进程并处理失败的工作进程的协调进程。您将构建类似于MapReduce论文的东西。&#xff08;注意&#xff1a…

Kafka进阶_1.生产消息

文章目录 一、Controller选举二、生产消息2.1、创建待发送数据2.2、创建生产者对象&#xff0c;发送数据2.3、发送回调2.3.1、异步发送2.3.2、同步发送 2.4、拦截器2.5、序列化器2.6、分区器2.7、消息可靠性2.7.1、acks 02.7.2、acks 1(默认)2.7.3、acks -1或all 2.8、部分重…

SpringBoot多环境配置的实现

前言 开发过程中必然使用到的多环境案例&#xff0c;通过简单的案例分析多环境配置的实现过程。 一、案例 1.1主配置文件 spring:profiles:active: prod server:port: 80801.2多环境配置文件 开发环境 blog:domain: http://localhost:8080测试环境 blog:domain: https:/…

鸿蒙HarmonyOS 地图定位到当前位置 site查询等操作

应用服务Map使用 地图定位 地点查询及导航 周边查询 点位标记定义等 地图定位 前提地图已经能正常显示&#xff0c;若不能显示请大家参考之前的那篇如何显示地图的博文 地图相关的api 位置效果图&#xff1a; module.json5配置权限 "requestPermissions": [{&…

AntFlow 0.11.0版发布,增加springboot starter模块,一款设计上借鉴钉钉工作流的免费企业级审批流平台

AntFlow 0.11.0版发布,增加springboot starter模块,一款设计上借鉴钉钉工作流的免费企业级审批流平台 传统老牌工作流引擎比如activiti,flowable或者camunda等虽然功能强大&#xff0c;也被企业广泛采用&#xff0c;然后也存着在诸如学习曲线陡峭&#xff0c;上手难度大&#x…

Timeline动画「硬切」的问题

1&#xff09;Timeline动画「硬切」的问题 2&#xff09;移动平台纹理压缩格式选择ASTC&#xff0c;美术出图还需遵守POT吗 3&#xff09;如何去掉DOTS Unity.Entities.Graphics创建的BatchRendererGroup的UI相机回调 4&#xff09;Timeline播放动画会产生位移的问题 这是第409…

《设计模式》创建型模式总结

目录 创建型模式概述 Factory Method: 唯一的类创建型模式 Abstract Factory Builder模式 Prototype模式 Singleton模式 最近在参与一个量化交易系统的项目&#xff0c;里面涉及到用java来重构部分vnpy的开源框架&#xff0c;因为是框架的搭建&#xff0c;所以会涉及到像…

【论文阅读】主动推理:作为感知行为的理论

文章目录 主动推理&#xff1a;作为感知行为的理论摘要1.引言2. 主动推理的概念和历史根源3. 主动推理的规范视角—以及它的发展历程 未完待续 主动推理&#xff1a;作为感知行为的理论 Active inference as a theory of sentient behavior 摘要 这篇文章综述了主动推理的历…