吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6555|回复: 37
上一主题 下一主题
收起左侧

[2021] 2021腾讯PC客户端初赛题解(对大佬解题手法的学习)

  [复制链接]
跳转到指定楼层
楼主
奋进的小杨 发表于 2021-4-15 15:22 回帖奖励
这道题,我当时没有做出来,有思路,但是感觉总差一点东西。最近看到了一些帖子,是关于这个,写的很好。我也学到了很多。今天这个帖子,一方面是由于很久没有发了,另一方面也是希望可以学到东西。
——题记
  • 前期的准备
a. 查壳通过工具,发现没有壳,同时也可以知道一些段的信息。这里不多做赘述。


b. 运行观察直接正常运行程序,发现该程序有一下的特点。第一,标题是XDDDDDDDD;第二,有一个画布,上面有一个箭头,感觉是一种提示;第三,鼠标光标消失,并且屏幕随鼠标移动。


c. 发现线索在上面的基础上,认为可以有一下的线索。第一,搜索字符串,“XDDDDDDDD”;第二,搜索读取桌面鼠标的IPA,WindowsFromPoint;第三,可能存在ASLR。
  • 验证以上猜想,打开OD,ALT+T,搜索字符串,果然结果如下:

这里很显然,这个函数,需要压入5 个参数,大胆认为,这里是构造窗口的。
  • 搜索WindowsFromPoint,得到的结果如下:

然后这里的上下文还有很多其他的API及作用,也一并将它们贴出来,分享一下。windowFromPoint: 获取鼠标位置的窗口句柄
GetImeHotKey: 重映射鼠标按键;
SetImeHotkey: 同上,相互呼应
CreateEmptyCursorObject:创建空的光标
DestroyCursor: 摧毁光标
GetControlBrush:控制
GetDC: 从一个设备上下文(DC)中提取一个句柄
GetThreadState:创建一个线程
GetIconSize: 得到图标的大小
  • 载入OD,动态调试一下,发现每次的基地址都不一样,所以很显然,这里存在ASLR。需要我们使用PE工具,来关闭ASLR。对于什么是ALSR,文章的最后面,我会回答大家。
2.        关闭ASLR,分析主函数通过ALSR disabler来关闭ALSR。
然后重新载入IDA,通过动态调试,可以定位到winmain(这个地方,如果没有看到,那就就需要载入后,逐步单步跟踪,那麽一定会看到的。)F5得到如下的伪代码:int __stdcall sub_406360(HMODULE hModule, int a2, int a3, int a4)                                       //_stdcall,约定函数
{
  char *v4; // esi@1
  DWORD v5; // ebx@1
  HANDLE v6; // eax@1
  void *v7; // edi@1
  void *v8; // ebx@3
  DWORD v9; // edi@3
  HANDLE v10; // eax@3
  void *v11; // esi@3
  LONG lDistanceToMove; // [sp+Ch] [bp-110h]@1
  void *lpBuffer; // [sp+10h] [bp-10Ch]@1
  LPVOID lpBuffera; // [sp+10h] [bp-10Ch]@3                                                           //缓冲区
  DWORD NumberOfBytesRead; // [sp+14h] [bp-108h]@2
  CHAR Filename; // [sp+18h] [bp-104h]@1                                                                //文件名

  v4 = (char *)hModule + *(_DWORD *)((char *)hModule + *((_DWORD *)hModule + 15) + 84);       //这里的hModule,栈指针,所以这里是开辟空间
  sub_4245A0(&Filename, 0, 256);                                                            //这里应该是定义这个文件的文件名。
  GetModuleFileNameA(hModule, &Filename, 0x100u);                                           //获取文件路径
  lDistanceToMove = *((_DWORD *)v4 - 2);                                                      //移动距离
  sub_407380(*((_DWORD *)v4 - 3));
  lpBuffer = (void *)dword_465FE4;                                                         //缓冲区的指针
  v5 = dword_465FE8 - dword_465FE4;
  v6 = CreateFileA(&Filename, 0x80000000, 1u, 0, 3u, 0x80u, 0);                               //创建文件,以及相关的格式
  v7 = v6;                                                                                 
  if ( v6 != (HANDLE)-1 )                                                                     //这里是为了防止文件为空或者有问题
  {
    SetFilePointer(v6, lDistanceToMove, 0, 0);                                             // 这里姑且认为是重新调整文件的指针
    NumberOfBytesRead = 0;
    ReadFile(v7, lpBuffer, v5, &NumberOfBytesRead, 0);                                  //读取缓冲区的内容V5字节,到文件中,并从0开始存放
    CloseHandle(v7);
  }
  lpBuffera = (LPVOID)*((_DWORD *)v4 - 4);                                                   //下面的同上,是为了创建另一个文件。
  sub_407380(*((_DWORD *)v4 - 5));
  v8 = ::lpBuffer;
  v9 = dword_465FF8 - (_DWORD)::lpBuffer;
  v10 = CreateFileA(&Filename, 0x80000000, 1u, 0, 3u, 0x80u, 0);
  v11 = v10;
  if ( v10 != (HANDLE)-1 )
  {
    SetFilePointer(v10, (LONG)lpBuffera, 0, 0);
    NumberOfBytesRead = 0;
    ReadFile(v11, v8, v9, &NumberOfBytesRead, 0);
    CloseHandle(v11);
  }
  return sub_4064D0();
}
为了更加清晰,这里采用OD,来动态调试一下,ctrl+G,搜索GetModuleFileNameA,然后F2,下断点。然后运行。

然后通过OD插件:用来将内存窗口中按照指定字节数选中数据并将数据保存到硬盘,点击可以下载。题目需要我们找到flag,所以我们需要把这些图的内存找到。注意到这一部分,很特殊,这里存储的是浮点数,如下图;
很显然,这里存储的就是这些图的内存。这个时候,寄存器的值如下:

选择相应的内存格式,发现这一部分,存储的都是坐标。
这个时候,就需要使用上面的插件,将这里的内存数据给dump下来,然后将它们使用代码,转换成数字。(下面,是我借鉴别人的代码)#include <iostream>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <stdlib.h>
using namespace std;
#pragma warning(disable:4996)
#define FILEFATH "F:\\腾讯游戏安全\\dump.dat"
typedef struct
{
      float x;
      float y;
      float z;
}st;
int main()
{
      FILE* fp = fopen(FILEFATH, "r");
      fseek(fp, 0, SEEK_END);
      DWORD file_size = ftell(fp);
      fseek(fp, 0, SEEK_SET);

      freopen("d:\\testout.txt", "w", stdout);

      printf("list1 = [");

      for (int i = 0; i < 1019; i++)
      {
              st t;
              fread(&t, sizeof(st), 1, fp);
              printf(",[%f,%f,%f]", t.x, t.y, t.z);
      }
      cout << "]";
      return 0;
}
然后通过python来显示,画图。import numpy as np
import matplotlib.pyplot as plt

list1 = [37.000000, 9.000000, -6.500000], [38.000000, 9.000000, -4.100000], [39.000000, 9.000000, -5.900000],
       [40.000000, 9.000000, -4.600000], [41.000000, 9.000000, -7.000000], [73.000000, 9.000000, -5.600000],
       [74.000000, 9.000000, -4.200000], [75.000000, 9.000000, -6.400000], [76.000000, 9.000000, -5.600000],
       [77.000000, 9.000000, -4.000000], [36.000000, 10.000000, -4.300000], [37.000000, 10.000000, -6.400000],
       [38.000000, 10.000000, -4.700000],
      ...(省略大部分数据)
      ]
fig = plt.figure()
ax1 = fig.add_subplot(111)
# 设置标题
ax1.set_title('ANSWER')
# 设置X轴标签
plt.xlabel('X')
# 设置Y轴标签
plt.ylabel('Y')
# 画散点图
for elist in list1:
  ax1.scatter(elist[0], elist[1], c='r', marker='.')
# 设置图标
plt.legend('x1')
# 显示所画的图
plt.show()
最后就得到了flag


3.       另类解法,修改参数这里采用的是CE。这里我们需要使用到ALT +TAB来切换界面。因为直接拖入,无法载入,但是我们可以打开这个目标文件,然后在CE上挂起。
  • 采用FSP游戏的寻找基址的方法,选择未知数值,然后回到游戏,再选择首次扫描,变动数值,然后再回到游戏。这样的方法,抓取游戏的数值。
  • 但是这里的地址,还是太多,需要我们不断过滤。最后剩余4个地址,

  • 然后不断修改视角,下内存访问断点。这里比较耗时,我还赶着做事情,没有找到满意的,所以我就借鉴一张别人的图。

  • 然后回到视图,就可以看到了flag。

     4.       总结
  • 什么是ASLR?它是一种安全策略,中文就是地址随机,主要是为了防止缓冲区溢出问题。ASLR包括随机排列程序的关键数据区域的位置,包括可执行的部分、堆、栈及共享库的位置。那么我们怎样来判断,一个exe文件是ASLR,还是重定位了?可重定位模块(exe或dll)不一定需要启用ASLR,但是启用了ASLR的模块需要可重定位。不可重定位的模块将在其文件头的"特征"字段中设置IMAGE_FILE_RELOCS_STRIPPED(0x0001)位标志.可重定位模块将清除此位,并且还将包含带有重定位的节(如.reloc).您可以使用PEView或dumpbin /headers your_module.exe(或dll)之类的软件检查该标志启用了ASLR的模块将可重定位(未设置重定位剥离标志),并且还将在可选标头的DllCharacteristics字段中设置IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE(0x0040)标志.不论其名称是什么,DllCharacteristics都用于EXE和DLL.
    所以我们可以检查这个标志。
  • 其实在分析程序的时候,可以看到一个_security_cookie,并且每一次循环,都要对这个进行一次验证。其实这里是一种GS,当我们编译程序的时候,可以在属性里面设置。这是GS,原理就是调用函数初始化一个栈帧之后将一个随机数放入栈当中,并且在“.data“节区保存一个副本。每次在执行返回地址得指令之前都需要验证一下随机值。如果发生变化,则认为产生溢出。最初的时候,我没有做出来,也是一直在钻这个GS的牛角尖,结果没有做出来。

  • 看了网上的评论,说这道题与18年的很像,可惜了,我没有看,也是自己对这方面的解题做的太少。当然了看到网上很多这样的解题方法,觉得自己也是豁然开朗,学到了很多。

附件中,是关于关闭ALSR的工具,请君取用。




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

免费评分

参与人数 14吾爱币 +13 热心值 +10 收起 理由
mantuner + 1 + 1 热心回复!
fanny188 + 1 我很赞同!
card628 + 1 我很赞同!
YMYS + 1 + 1 用心讨论,共获提升!
xdxf2000 + 1 + 1 热心回复!
爱你小吉君 + 1 谢谢@Thanks!
wapjxcg + 1 + 1 用心讨论,共获提升!
wuai.kk + 1 用心讨论,共获提升!
fork + 1 + 1 我很赞同!
kdrew + 1 + 1 热心回复!
Service123 + 1 + 1 我很赞同!
xiaoma809607 + 1 用心讨论,共获提升!
Noyi + 1 + 1 我很赞同!
shiina0831 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
Hmily 发表于 2021-4-15 18:19
3#
kbxy 发表于 2021-4-15 18:45
4#
shiina0831 发表于 2021-4-15 19:05
5#
HelloGirl 发表于 2021-4-15 21:39
这题我做了 还答对了..但看你这案例我没看懂 图乱的 然后怎么找到浮点数 没说清楚啊
6#
liuking0512 发表于 2021-4-15 21:39
支持,大佬厉害
7#
Kingmxp 发表于 2021-4-15 21:51
支持,力挺!
8#
wzz1 发表于 2021-4-15 22:58
厉害啊 大佬
9#
keithljp 发表于 2021-4-15 23:04
大神大神,牛批
10#
jiangbingren 发表于 2021-4-15 23:11
大神,太厲害了   
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-27 06:39

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表