[安洵杯 2019]crackMe

2024-05-25 00:44
文章标签 2019 crackme 安洵

本文主要是介绍[安洵杯 2019]crackMe,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

直接就退出程序了

找到关键函数了,好像用到了 hook

还有一个

嘿嘿,看着就是像 base64 只是 补‘=’改成了‘ ! ’

交叉引用啊,翻到一个应该是最后比较函数

1UTAOIkpyOSWGv/mOYFY4R!!

那一坨对 a1数组的操作没看懂

先总结一下就是 有一个大小写转换,类base64,两两交换位置,1,2,3

先解码得到乱码,估计就是后面两个先,123,132,312,321应该就这四种情况

试了两个没搞出来,烦 0_0 

靠,是对base表进行了大小写转换

看wp感觉自己分析的还是有点问题

这是main函数报红处汇编,扒到一个函数

都是在对字节的操作

就是 a2字节序改变-->v5[0-3] , 对a1异或-->v5[4-35],最后 v5[32-35]取字节-->a3

v5[i] = v5[i+4]^sub_411760(v5[i+1]^v5[i+2]^v5[i+3]^(key+4*i))

 en , y 是 用户输入 ,知道 y , z 就可以求出 x 

那就对 y z 进行交叉引用

对 x   

没有与输入的操作,可以直接动调获取

Handler_0第9行,这里注册了一个UEH函数,看看

在Windows编程中,UEH(Unhandled Exception Handler)通常指未处理异常处理器,处理程序在应用程序发生未处理的异常时执行特定的操作。在Windows中,可以使用 SetUnhandledExceptionFilter 函数来设置未处理异常的处理程序,可以帮助你在未处理的异常发生时更好地调试和维护应用程序。

额,别人的是这样的

(v3 >> (6 * (3 - k))) & 0x3F

(6*(3-k))计算位移量  ,

(v3>>x)&0x3f  -->偏移后结果只取其二进制的低6位

v3 >> (6 * (3 - 1)) = v3 >> 12
v3 = 0x12345678
0x12345678 >> 12 = 0x00012345
0x00012345 & 0x3F = 0x05  // 二进制: 00000101

对Table进行凯撒偏移24位

UEH这个函数返回时eip被修改为sub_121136,去看看,发现了最初比较函数

其实还没完,Hadler_0(对x交叉引用找到的)是如何被调用的,对其交叉引用

是注册了一个VEH函数来调用的

在Windows操作系统中,VEH(Vectored Exception Handling)是一种高级的异常处理机制,允许应用程序注册和管理异常处理程序。VEH提供了一种机制,可以在异常处理的各个阶段(包括未处理异常阶段)插入自定义处理程序。

再后面的 wp 就更有点懵逼了

继续往上面翻,找到了这个

int __cdecl sub_1227B0(int a1, char *String2, int a3)
{DWORD LastError; // eaxDWORD flOldProtect[3]; // [esp+D0h] [ebp-90h] BYREFint (__stdcall *v6[3])(int, int, int, int); // [esp+DCh] [ebp-84h] BYREFLPCVOID lpAddress; // [esp+E8h] [ebp-78h]struct _MEMORY_BASIC_INFORMATION Buffer; // [esp+F4h] [ebp-6Ch] BYREFLPVOID lpBaseAddress; // [esp+118h] [ebp-48h]int v10; // [esp+124h] [ebp-3Ch]char *String1; // [esp+130h] [ebp-30h]int i; // [esp+13Ch] [ebp-24h]int v13; // [esp+148h] [ebp-18h]int v14; // [esp+154h] [ebp-Ch]v14 = a1;v13 = a1 + *(_DWORD *)(a1 + 60) + 24;for ( i = *(_DWORD *)(v13 + 104) + a1; i; i += 20 ){String1 = (char *)GetModuleHandleW(0) + *(_DWORD *)(i + 12);if ( !stricmp(String1, String2) )break;}if ( !i )return 0;v10 = *(_DWORD *)(i + 16) + a1;if ( !v10 )return 0;while ( 1 ){if ( !*(_DWORD *)v10 )return 0;lpBaseAddress = (LPVOID)v10;if ( *(_DWORD *)v10 == a3 )break;v10 += 4;}lpAddress = (LPCVOID)(v10 >> 12 << 12);VirtualQuery(lpAddress, &Buffer, 0x3E8u);VirtualProtect((LPVOID)lpAddress, Buffer.RegionSize, 0x40u, &Buffer.Protect);v6[0] = sub_121023;if ( WriteProcessMemory((HANDLE)0xFFFFFFFF, lpBaseAddress, v6, 4u, 0) ){VirtualProtect(Buffer.BaseAddress, Buffer.RegionSize, Buffer.Protect, flOldProtect);return 1;}else{LastError = GetLastError();printf("%d\n", LastError);return 0;}
}

对里面调用的函数进行符号还原,前面就是找到 user32.dll 对应的 IMAGE_IMPORT_DESCRIPTOR 结构体地址,然后找到 MessageBoxW 对应的 IMAGE_THUNK_DATA 结构体地址,用VirtualProtect修改页属性为可写,用WriteProcessMemory将IMAGE_THUNK_DATA字段覆写为sub_121023函数地址

总结一下,典型的IAT hook,将MessageBoxW的IAT地址替换为了sub_411023的函数地址,该函数完成了VEH的注册

还没完,继续分析这个IAT hook函数是被谁调用的,引用回溯到了rdata这里,往上翻翻

就是sub_121e40继续往上

这个地方被tmainCRTStartup调用了 ?

就是上面那个调用是在tmainCRTStartup里应该

看看tmainCRTStartUp函数,32行这里initterm_e调用了rdata区域里保存的函数,对全局/静态C++类的构造函数进行了初始化

// write access to const memory has been detected, the output may be wrong!
int __tmainCRTStartup()
{int v1; // [esp+18h] [ebp-24h]signed __int32 v2; // [esp+1Ch] [ebp-20h]signed __int32 v3; // [esp+20h] [ebp-1Ch]v2 = *(_DWORD *)(j__NtCurrentTeb() + 4);v1 = 0;while ( 1 ){v3 = _InterlockedCompareExchange(dword_12A6EC, v2, 0);if ( !v3 )break;if ( v3 == v2 ){v1 = 1;break;}}if ( dword_12A6FC == 1 ){j__amsg_exit(31);goto LABEL_13;}if ( dword_12A6FC ){dword_12A2DC = 1;goto LABEL_13;}dword_12A6FC = 1;if ( !j__initterm_e((_PIFV *)&First, (_PIFV *)&Last) ){
LABEL_13:if ( dword_12A6FC == 1 ){j__initterm((_PVFV *)&dword_127000, (_PVFV *)&dword_127208);dword_12A6FC = 2;}if ( dword_12A6FC != 2&& CrtDbgReportW(2,L"f:\\dd\\vctools\\crt\\crtw32\\dllstuff\\crtexe.c",553,0,L"%s",L"__native_startup_state == __initialized") == 1 ){__debugbreak();}if ( !v1 )_InterlockedExchange(dword_12A6EC, 0);if ( dword_12A714 ){if ( j___IsNonwritableInCurrentImage(&dword_12A714) )dword_12A714(0, 2, 0);}CrtSetCheckCount(1);_initenv = envp;main(argc, (const char **)argv, (const char **)envp);}return 255;
}

en, 从结果一步步推导原因,这就很 reverse

上面的分析是根据结果查找原因,倒着推回去的比较乱,下面再梳理总结下

异常处理的注册

  • 程序初始化时,调用链为start->tmainCRTStartUp->initterm_e->IAT hook,修改MessageBoxW函数的IAT表,在主函数中调用MessageBoxW,实际调用的是注册VEH的函数,并对base64编码表进行了变换
  • 在main函数中对SEH进行了注册
  • 在VEH handler中对UEH进行了注册

异常处理的回调

  • 需要知道一个知识点,Windows 用户态异常发生先找调试器,没有再找 VEH,VEH 处理不了再找 SEH, SEH 还处理不了找 UEF

  • main函数中触发内存写异常,本程序各级异常处理的返回状态都是未完成处理,会继续往下级调异常处理函数,所以本程序的调用顺序为VEH->SEH->UEH

  • VEH中对sm4的box进行了初始化

  • SEH中对input进行sm4加密,获得output

  • UEH中对output进行变种的base64加密,获得Str1,并且和变换过的固定字符串Str2进行比较

总之,题目的算法分析和还原很简单,麻烦的是这些算法没有集中在main中,而是分散到了各个异常处理函数里面,跳来跳去的对分析造成了干扰,不过只要足够有耐心,不断向上查找引用,还是能分析完的

https://www.cnblogs.com/z5onk0/p/17506136.html

嗯,也是一道经典的 hook 题了,很多相关知识需要学学。

 被误导了,不是凯撒

import base64
import sm4
table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
# base表大小写转换
new_table=''
for char in table:tmp=ord(char)if 97<=tmp<=122:new_table+=chr(tmp-32)elif 65<=tmp<=90:new_table+=chr(tmp+32)else:new_table+=char
# base表 %24
table+='='
test=new_table
new_table=new_table[24:]+new_table[:24]+'!'
def kaisha(enc):str=''for char in enc:tmp=ord(char)if 97<=tmp<=122:if tmp+24<=122:str+=chr(tmp+24)else:str+=chr(tmp+24-122+97)elif 65<=tmp<=90:if tmp+24<=90:str+=chr(tmp+24)else:str+=chr(tmp+24-90+65)else:str+=charreturn str
print(new_table)
print(kaisha(test)+'!')str2="1UTAOIkpyOSWGv/mOYFY4R!!"
# 字符串两两交换
str2_swap=''
for i in range(0,len(str2)-1,2):str2_swap+=str2[i+1]+str2[i]# base64解密
b64str=''
for str in str2_swap:b64str+=table[new_table.find(str)]
enflag=base64.b64decode(b64str)# sm4 解密
key=sm4.SM4Key(b"where_are_u_now?")
flag=key.decrypt(enflag)
print(flag)

这篇关于[安洵杯 2019]crackMe的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1000005

相关文章

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

新160个crackme - 051-Keygenning4newbies

运行分析 需要破解Name和Serial PE分析 C++程序,32位,无壳 静态分析&动态调试 ida找到关键字符串,双击进入函数 静态分析得到以下结论:1、Name长度要大于4,小于502、v5 += Name[i] ^ (i + 1)3、v7 = 最后一个Name[i] ^ (i + 1)4、Serial = (v5<<7) + 6* v7 的16进制

新160个crackme - 050-daxxor

运行分析 需要破解Name和Serial PE分析 C++程序,32位,无壳 静态分析&动态调试 ida找到关键字符串,双击进入函数 通过静态分析发现:1、Name通过计算得到Name12、对Name1第3、5、6分别插入byte_401290、byte_401290、word_401292,得到Name23、双击byte_401290,发现值为0x2D;双

2019学习计划

工作三年了,第一年感觉是荒废的,第二年开始学习python,第三年开始自动化 感觉自己会的东西比较少,而且不够深入,流于表面 现制定一下今年大概的学习计划 需持续巩固加强:python、ui自动化、接口自动化、sql等 代码量需提升,敲的不够(重点) 学习: 1.移动端测试,appium等 2.前端知识系统整理学习  3.性能测试 4.docker入门,环境搭建 5.shell

最简单的使用JDBC[连接数据库] mysql 2019年3月18日

最极简版本的, 我们这里以mysql为例: 首先要创建maven工程, 需要引入jar包:,这里需要注意, 如果你安装的是mysql最新版本8以上的, 下面有些地方需要更改,具体就是mysql连接的url, 和5版本的不一样,具体解决请自行百度哈.这里只演示mysql5版本的? 依赖: <dependency>   <groupId>mysql</groupId>   <artifactId

(php伪随机数生成)[GWCTF 2019]枯燥的抽奖

审核源码发现加载check.php,审计发现使用了mt_rand()函数,这个函数生成的值是伪随机的 参考下面这篇文章 PHP mt_rand安全杂谈及应用场景详解 - FreeBuf网络安全行业门户 kali里面输入下载工具 git clone https://github.com/openwall/php_mt_seed.git cd进去输入make后编译出的文件先

2019年2月17日

今天又重新看了一下输出第1500个丑数 在我错了八次之后发现要输出一个句号还要输出换行 接下来的两天应该进入复习阶段了。

National Contest for Private Universities (NCPU), 2019 E. Generalized Pascal's Triangle

编辑代码 2000ms 262144K Generalized Pascal's Triangle Pascal's triangle is a triangular array in which each number can be calculated by the sum of the two numbers directly above that number as shown i

Hinton等人最新研究:大幅提升模型准确率,标签平滑技术 2019-7-8

导读:损失函数对神经网络的训练有显著影响,也有很多学者人一直在探讨并寻找可以和损失函数一样使模型效果更好的函数。后来,Szegedy 等学者提出了标签平滑方法,该方法通过计算数据集中 hard target 的加权平均以及平均分布来计算交叉熵,有效提升了模型的准确率。近日,Hinton 团队等人在新研究论文《When Does Label Smoothing Help?》中,就尝试对标签平滑技术对

Photoshop CC 2019圆形的抠图

快速进入矩形选区 快速在矩形和圆形选区之前切换: shift+M 选择的时候,按住shift,可以选中正方形/圆形   以中心点画圆: alt + 拖拽 再利用变换选区功能即可实现圆的选中 效果如图所示: 再使用自由变换,即可放大,缩小球的大小: ctrl + T 阴影部分的处理: 1)去其他球那里选择个椭圆形选区 2)选择编辑-填充 3)使用滤镜里