[HuhstSec实验室]学习
逆向IDA工具的使用 ida两个图标,区别是一个用于打开32位程序,一个用于打开64位程序
拿到程序首先用exeinfope检查该程序是多少位的
函数窗口
一般从main函数开始解决,搜索定位至main
汇编代码窗口图形模式
可右键text view进入文本模式,也可通过空格来回切换
下图为16进制模式
在主函数界面按f5进入函数页面
按tab来回切换
shift+f12 进入字符界面
alt+t 可以查找文字
CTRL+x 交换引用,选中该函数后CTRL+x,可以看到是否有其他函数调用了该函数
离开前先复制地址
g键可调回来
右键 add a comment 为关键语句添加注释
转换为汇编代码
CTRL+1回到最初的位置😎
即刚打开文件时的位置
保存操作
不保存操作
右键数据可为数据转换形式
ida同样可以做到动态调试
使用ida内的keypatch中的patcher可以修改命令
使其jnz改成jz,直接跳转到所需位置
函数调用图 菜单栏中:view–>graphs–>Function calls(快捷键Ctrl+F12)
折叠流程图中的分支 在流程视图中,分支过多的时候,可以在窗口标题处右击选择group nodes,就能把当前块折叠起来
手工创建结构体 创建结构体是在IDA的structures窗口中进行的,这个操作在堆漏洞的pwn题中经常使用
可以右击选择hide/unhide,来看具体的结构体的内容
创建结构体的快捷键是:insert
在弹出的窗口中,可以编辑结构体的名字
这底下有三个复选框,第一个表示显示在当前结构体之前(就会排列在第一位,否则排列在你鼠标选定的位置),第二个表示是否在窗口中显示新的结构体,第三个表示是否创建联合体。
需要注意的是,结构体的大小是它所包含的字段大小的总和,而联合体的大小则等于其中最大字段的大小
在单击ok以后,就定好了一个空的结构体
将鼠标放在 ends这一行,单击快捷键D即可添加结构体成员,成员的命名默认是以field_x表示的,x代表了该成员在结构体中的偏移
同时,可以把鼠标放在结构体成员所在的行,按D,就可以切换不同的字节大小
默认情况下可供选择的就只有db,dw,dd(1,2,4字节大小)
如果想添加型的类型,可以在option–>setup data types(快捷键Alt+D),进行设置
导入C语言声明的结构体 实际上,IDA有提供一个更方便的创建结构体的方法,就是直接写代码导入
在View–>Open Subviews–>Local Types中可以看到本地已有的结构体,在该窗口中右击insert
可以添加新的结构体:
但同时我们发现structure视图里面,并没有这个结构体,我们需要对着my_structure右击,选择 synchronize to idb
IDA-python 在IDA的最下面有个不起眼的Output Window的界面,其实是一个终端界面,这里有python终端和IDC终端
这里的python是2.7的版本,虽然老了点,但已经足够我们用了,在IDA的运用中,我们经常需要计算地址,计算偏移,就可以直接在这个终端界面进行操作,非常方便
当然上面说的只是很简单的python用法,真正的IDA-python的用法是这样的:
这里以简单的一道逆向题来做个例子
把judge的内容全部异或
judge函数就寄了
从而使得没法进行后面的flag判断
这里我们就需要写一个脚本来先把被破坏的内容还原,这里IDA提供了两种写脚本操作的方法,一种就是IDC脚本,一种就是python脚本
针对以上的题目,我们只需要做一个脚本,指定judg函数的0-181范围的字节异或0xc,即可恢复
这里我们就需要写一个脚本来先把被破坏的内容还原,这里IDA提供了两种写脚本操作的方法,一种就是IDC脚本,一种就是python脚本
这里只简单的介绍IDA-python
而IDA-python通过三个python模块将python代码注入IDA中:
idaapi模块负责访问核心IDA API
idc模块负责提供IDA中的所有函数功能
idautils模块负责提供大量实用函数,其中许多函数可以生成各种数据库相关对象的python列表
所有的IDApython脚本会自动导入idc和idautils模块,而idaapi模块得自己去导入
这里贴上IDApython的官方函数文档 ,这里包含了所有函数,值得一看
针对以上的题目,我们只需要做一个脚本,指定judg函数的0-181范围的字节异或0xc,即可恢复
1 2 3 4 5 6 judge=0x600B00 #judge的地址 for i in range(182): addr=0x600B00+i byte=get_bytes(addr,1)#获取指定地址的指定字节数 byte=ord(byte)^0xC patch_byte(addr,byte)#打patch修改字节
在菜单栏中file–>script file,加载python脚本
接着在judge函数中undefined掉原来的函数,在重新生成函数(快捷键p),就可以重新f5了 脚本中出现的函数都是已经封装在idc模块中的,具体可查官方文档
打PATCH 打patch,其实就是给程序打补丁,本质上是修改程序的数据,指令等,这在CTF中的AWD赛制中经常用到,发现程序漏洞后马上就要用这个功能给程序打好patch,防止其他队伍攻击我们的gamebox
这里,我是用一个叫keypatch的插件进行操作的,IDA自带的patch功能不太好用
安装keypatch 教程在github 就有
下载Keypatch.py复制到插件目录
IDA 7.0\plugins\Keypatch.py
下载安装keystone python模块,64位系统只需要安装这一个就行
https://github.com/keystone-engine/keystone/releases/download/0.9.1/keystone-0.9.1-python-win64.msi
打patch后
接着还要在菜单栏进行设置才能真正使得patch生效
这样一来,原来的程序就已经被修改了
撤销patch 如果不小心打错了patch,就可以在这里进行撤销上一次patch的操作了
但是如果打了很多次patch,不好分清该撤销哪一次的patch,那么可以在菜单栏中打开patched bytes界面
看到所有的patch,要撤销哪一个就右击选择 revert
IDA导出数据文件 在菜单栏中,这里有个选项可以生成各种不同的输出文件
这里简单的介绍前两个文件,后面的大家可以自己去生成测试一下用途,我这里就不详细介绍了
.map文件描述二进制文件的总体结构,包括与构成改二进制文件的节有关的信息,以及每个节中符号的位置。
.asm文件,也就是汇编了,直接能导出ida中反汇编的结果,这个非常实用,有的时候在逆向中经常遇到大量数据加解密的情况,如果在从IDA中一个个慢慢复制可就太没效率了,直接导出生成asm,在里面复制数据快很多
IDA常见命名意义 sub 指令和子函数起点 locret 返回指令 loc 指令 off 数据,包含偏移量 seg 数据,包含段地址值 asc 数据,ASCII字符串 byte 数据,字节(或字节数组) word 数据,16位数据(或字数组) dword 数据,32位数据(或双字数组) qword 数据,64位数据(或4字数组) flt 浮点数据,32位(或浮点数组) dbl 浮点数,64位(或双精度数组) tbyte 浮点数,80位(或扩展精度浮点数) stru 结构体(或结构体数组) algn 对齐指示 unk 未处理字节
IDA中有常见的说明符号,如db、dw、dd分别代表了1个字节、2个字节、4个字节
IDA反编译报错 目前来说, 我遇到的反编译报错的情况,一般是两种
一是由于程序存在动态加密,导致程序的某些代码段被修改,从而反编译出错,这种情况,就需要去使用IDA-python解密一波,再进行F5反汇编
二是由于某些玄学问题,直接提示了某个地方出错,一般来说,就按照IDA的提示,去进行修改
比如,出现如下报错:
那我们就去找413238这个地址的地方,提示是说sp指针的值没有被找到,说明是这里出错了,那么就去修改sp的值,修改方法如下:
也可以使用快捷键 Alt+K
有的时候,遇到的这种报错
就尝试着把报错的地址的汇编语句改一哈,改成nop,就可以解决问题
目前来说,我遇到报错的情况不多,一般都可以通过以上方法解决
解题思路
使用查壳工具Exeinfope、detect is easy 查看文件的属性,通过他的属性决定对应的使用工具
打开对应ida找到主函数,或找到其他加密点
分析程序的加密逻辑
逆推逻辑写出脚本解出flag
64位程序且无壳
有时候他给个elf文件,是Linux的可执行文件,与exe文件类似,不能在Windows下直接运行,但也可直接拖进ida分析,
C#撰写时用Reflector软件将其打开
pyc格式用在线python反编译工具
ollydbg CTRL+G定位函数
F2下断点,按下F9运行,程序会停在断点这个地方,然后按F8(单步步过,遇到call不进去)
F4运行到所选位置
软件破解流程 先说一下一般软件破解的流程:拿到一个软件先别接着马上用 OllyDBG 调试,先运行一下,有帮助文档的最好先看一下帮助,熟悉一下软件的使用方法,再看看注册的方式。如果是序列号方式可以先输个假的来试一下,看看有什么反应,也给我们破解留下一些有用的线索。如果没有输入注册码的地方,要考虑一下是不是读取注册表或 Key 文件(一般称 keyfile,就是程序读取一个文件中的内容来判断是否注册),这些可以用其它工具来辅助分析。如果这些都不是,原程序只是一个功能不全的试用版,那要注册为正式版本就要自己来写代码完善了。有点跑题了,呵呵。获得程序的一些基本信息后,还要用查壳的工具来查一下程序是否加了壳,若没壳的话看看程序是什么编译器编的,如 VC、Delphi、VB 等。这样的查壳工具有 PEiD 和 FI。有壳的话我们要尽量脱了壳后再来用 OllyDBG 调试
upx 虚拟机带了个upxshell的
加upx壳工具,据说能脱壳,但是貌似没什么卵用
脱壳的话还是建议在开源社区下载upx 3.96 windows版本,个人习惯用Windows10虚拟机
使用方法:
将upx解压,
在左上角文件路径中输入cmd,在此处打开终端
upx sample_mal.exe
:显示加壳成功
可以用查壳工具看一下发现成功了
脱壳命令
同理
函数 strcat 将两个字符串连接
类似于python里的string直接相加
text = **(char )join *(key3, v9); 也是字符串相接的一种
strcpy 是将右边的字符串赋值给左边
strncpy替代strcpy 来防止缓冲区越界
总之功能差不多
bugku easy_re 方法一
找v5但是找不到
按A转化成字符形式,得到flag
方法2 扔进OD,用中文搜索插件直接搜到flag
方法三 flagget前面有个跳过语句,把他给断了,在寄存器窗口发现flag
easy_vb 方法一 拖进OD里,用插件查找字符,得到flag
但为了锻炼一下能力
方法二 直接运行
发现怎么点确定都没反应
中文搜索
跳转到欢迎来到网络安。。。。大赛
发现前面有一个jnz跳过了这句话,把这句话右键,二进制,用NOP填充
还不行
跳转到try again看看这之前干了什么
jmp跳过了try again,但是他还是输出了,再往上找,还有个往上跳的,也不对,再往上,发现je
绕过了这两个跳转使其输出try again
把je nop掉
还是不够
再努努力
往上找找
发现flag,但是我当没看见,在push下面打个断点,再调试
结束
树木的小秘密
发现是python,推测是python写的,打包成了exe文件,用ida打开,发现确实有很多py
把工具和待反编译的exe放到一个目录下
然后在cmd里执行
python pyinstxtractor.py easy_reverse.exe
显然这个123飞长的可疑
先用ex看了一下发现不是exe,后缀改成txt打开看一下
flag:z
ZmxhZ3tteV9uYW1lX2lzX3NodW11fQ==
后头俩等号
应该是base64
为了锻炼一下python
写了个代码
1 2 3 4 5 import base64 str = 'ZmxhZ3tteV9uYW1lX2lzX3NodW11fQ==' print(base64.b64decode(str))
然后。。
怎么也跑不起来
发现我tm文件夹里啊有个base64.py
大伙千万不要用import后面的东西来命名文件
游戏过关 查壳工具查看,发现是32位无壳程序
方法一 先查找main函数
发现关键代码
意思是n是灯的序列号,m是灯的状态 如果第n个灯的m是1,它就亮,如果不是,它就灭 起初所有的灯都关上了 现在您可以输入n来更改其状态 但是你应该注意一件事,如果你改变Nth的状态p、 (N-1)th和(N+1)th的状态也改变 所有灯亮起时,flag将出现 现在,输入n 输入n,n(1-8) 就是输入一个1到8之间的数,例如1:就会改变周围的三个数的状态,令8、1、2三个数变亮,再输入一个2:也会改变2周围三个数的状态,令1、2熄灭,3亮起。多次输入后,最后8个数都亮起的时候就会输出flag。
从1输到8,得出flag
当然这样做好像有点水(●’◡’●)
方法二
在ida底端发现通关条件
推测下面的函数是输出flag的函数
双击进入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 int sub_45E940() { signed int i; // [esp+D0h] [ebp-94h] char v2; // [esp+DCh] [ebp-88h] char v3; // [esp+DDh] [ebp-87h] char v4; // [esp+DEh] [ebp-86h] char v5; // [esp+DFh] [ebp-85h] char v6; // [esp+E0h] [ebp-84h] char v7; // [esp+E1h] [ebp-83h] char v8; // [esp+E2h] [ebp-82h] char v9; // [esp+E3h] [ebp-81h] char v10; // [esp+E4h] [ebp-80h] char v11; // [esp+E5h] [ebp-7Fh] char v12; // [esp+E6h] [ebp-7Eh] char v13; // [esp+E7h] [ebp-7Dh] char v14; // [esp+E8h] [ebp-7Ch] char v15; // [esp+E9h] [ebp-7Bh] char v16; // [esp+EAh] [ebp-7Ah] char v17; // [esp+EBh] [ebp-79h] char v18; // [esp+ECh] [ebp-78h] char v19; // [esp+EDh] [ebp-77h] char v20; // [esp+EEh] [ebp-76h] char v21; // [esp+EFh] [ebp-75h] char v22; // [esp+F0h] [ebp-74h] char v23; // [esp+F1h] [ebp-73h] char v24; // [esp+F2h] [ebp-72h] char v25; // [esp+F3h] [ebp-71h] char v26; // [esp+F4h] [ebp-70h] char v27; // [esp+F5h] [ebp-6Fh] char v28; // [esp+F6h] [ebp-6Eh] char v29; // [esp+F7h] [ebp-6Dh] char v30; // [esp+F8h] [ebp-6Ch] char v31; // [esp+F9h] [ebp-6Bh] char v32; // [esp+FAh] [ebp-6Ah] char v33; // [esp+FBh] [ebp-69h] char v34; // [esp+FCh] [ebp-68h] char v35; // [esp+FDh] [ebp-67h] char v36; // [esp+FEh] [ebp-66h] char v37; // [esp+FFh] [ebp-65h] char v38; // [esp+100h] [ebp-64h] char v39; // [esp+101h] [ebp-63h] char v40; // [esp+102h] [ebp-62h] char v41; // [esp+103h] [ebp-61h] char v42; // [esp+104h] [ebp-60h] char v43; // [esp+105h] [ebp-5Fh] char v44; // [esp+106h] [ebp-5Eh] char v45; // [esp+107h] [ebp-5Dh] char v46; // [esp+108h] [ebp-5Ch] char v47; // [esp+109h] [ebp-5Bh] char v48; // [esp+10Ah] [ebp-5Ah] char v49; // [esp+10Bh] [ebp-59h] char v50; // [esp+10Ch] [ebp-58h] char v51; // [esp+10Dh] [ebp-57h] char v52; // [esp+10Eh] [ebp-56h] char v53; // [esp+10Fh] [ebp-55h] char v54; // [esp+110h] [ebp-54h] char v55; // [esp+111h] [ebp-53h] char v56; // [esp+112h] [ebp-52h] char v57; // [esp+113h] [ebp-51h] char v58; // [esp+114h] [ebp-50h] char v59; // [esp+120h] [ebp-44h] char v60; // [esp+121h] [ebp-43h] char v61; // [esp+122h] [ebp-42h] char v62; // [esp+123h] [ebp-41h] char v63; // [esp+124h] [ebp-40h] char v64; // [esp+125h] [ebp-3Fh] char v65; // [esp+126h] [ebp-3Eh] char v66; // [esp+127h] [ebp-3Dh] char v67; // [esp+128h] [ebp-3Ch] char v68; // [esp+129h] [ebp-3Bh] char v69; // [esp+12Ah] [ebp-3Ah] char v70; // [esp+12Bh] [ebp-39h] char v71; // [esp+12Ch] [ebp-38h] char v72; // [esp+12Dh] [ebp-37h] char v73; // [esp+12Eh] [ebp-36h] char v74; // [esp+12Fh] [ebp-35h] char v75; // [esp+130h] [ebp-34h] char v76; // [esp+131h] [ebp-33h] char v77; // [esp+132h] [ebp-32h] char v78; // [esp+133h] [ebp-31h] char v79; // [esp+134h] [ebp-30h] char v80; // [esp+135h] [ebp-2Fh] char v81; // [esp+136h] [ebp-2Eh] char v82; // [esp+137h] [ebp-2Dh] char v83; // [esp+138h] [ebp-2Ch] char v84; // [esp+139h] [ebp-2Bh] char v85; // [esp+13Ah] [ebp-2Ah] char v86; // [esp+13Bh] [ebp-29h] char v87; // [esp+13Ch] [ebp-28h] char v88; // [esp+13Dh] [ebp-27h] char v89; // [esp+13Eh] [ebp-26h] char v90; // [esp+13Fh] [ebp-25h] char v91; // [esp+140h] [ebp-24h] char v92; // [esp+141h] [ebp-23h] char v93; // [esp+142h] [ebp-22h] char v94; // [esp+143h] [ebp-21h] char v95; // [esp+144h] [ebp-20h] char v96; // [esp+145h] [ebp-1Fh] char v97; // [esp+146h] [ebp-1Eh] char v98; // [esp+147h] [ebp-1Dh] char v99; // [esp+148h] [ebp-1Ch] char v100; // [esp+149h] [ebp-1Bh] char v101; // [esp+14Ah] [ebp-1Ah] char v102; // [esp+14Bh] [ebp-19h] char v103; // [esp+14Ch] [ebp-18h] char v104; // [esp+14Dh] [ebp-17h] char v105; // [esp+14Eh] [ebp-16h] char v106; // [esp+14Fh] [ebp-15h] char v107; // [esp+150h] [ebp-14h] char v108; // [esp+151h] [ebp-13h] char v109; // [esp+152h] [ebp-12h] char v110; // [esp+153h] [ebp-11h] char v111; // [esp+154h] [ebp-10h] char v112; // [esp+155h] [ebp-Fh] char v113; // [esp+156h] [ebp-Eh] char v114; // [esp+157h] [ebp-Dh] char v115; // [esp+158h] [ebp-Ch] sub_45A7BE("done!!! the flag is "); v59 = 18; v60 = 64; v61 = 98; v62 = 5; v63 = 2; v64 = 4; v65 = 6; v66 = 3; v67 = 6; v68 = 48; v69 = 49; v70 = 65; v71 = 32; v72 = 12; v73 = 48; v74 = 65; v75 = 31; v76 = 78; v77 = 62; v78 = 32; v79 = 49; v80 = 32; v81 = 1; v82 = 57; v83 = 96; v84 = 3; v85 = 21; v86 = 9; v87 = 4; v88 = 62; v89 = 3; v90 = 5; v91 = 4; v92 = 1; v93 = 2; v94 = 3; v95 = 44; v96 = 65; v97 = 78; v98 = 32; v99 = 16; v100 = 97; v101 = 54; v102 = 16; v103 = 44; v104 = 52; v105 = 32; v106 = 64; v107 = 89; v108 = 45; v109 = 32; v110 = 65; v111 = 15; v112 = 34; v113 = 18; v114 = 16; v115 = 0; v2 = 123; v3 = 32; v4 = 18; v5 = 98; v6 = 119; v7 = 108; v8 = 65; v9 = 41; v10 = 124; v11 = 80; v12 = 125; v13 = 38; v14 = 124; v15 = 111; v16 = 74; v17 = 49; v18 = 83; v19 = 108; v20 = 94; v21 = 108; v22 = 84; v23 = 6; v24 = 96; v25 = 83; v26 = 44; v27 = 121; v28 = 104; v29 = 110; v30 = 32; v31 = 95; v32 = 117; v33 = 101; v34 = 99; v35 = 123; v36 = 127; v37 = 119; v38 = 96; v39 = 48; v40 = 107; v41 = 71; v42 = 92; v43 = 29; v44 = 81; v45 = 107; v46 = 90; v47 = 85; v48 = 64; v49 = 12; v50 = 43; v51 = 76; v52 = 86; v53 = 13; v54 = 114; v55 = 1; v56 = 117; v57 = 126; v58 = 0; for ( i = 0; i < 56; ++i ) // flag逻辑 { *(&v2 + i) ^= *(&v59 + i); *(&v2 + i) ^= 0x13u; } return sub_45A7BE("%s\n"); }
flag的逻辑为将v2到到v57分别与v59到v114异或
再把v2到v57分别与0x13u异或
0x代表16进制将13转换为16进制
u不用管
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 a = [18,64,98,5,2,4,6,3,6,48,49,65,32,12,48,65,31,78,62,32,49,32, 1,57,96,3,21,9,4,62,3,5,4,1,2,3,44,65,78,32,16,97,54,16,44, 52,32,64,89,45,32,65,15,34,18,16,0] b = [123,32,18,98,119,108,65,41,124,80,125,38,124,111,74,49, 83,108,94,108,84,6,96,83,44,121,104,110,32,95,117,101,99, 123,127,119,96,48,107,71,92,29,81,107,90,85,64,12,43,76,86, 13,114,1,117,126,0] flag = '' for i in range(56): b[i] ^= a[i] b[i] ^= 19 flag += chr(b[i]) #i是从0到55,我看的题解里说是从v2到v58 #要相信自己的判断,存疑就自己写个脚本跑一下 #也就是说上面的ab列表最后的0可以删去 print(flag)
方法三 该题程序为32,可以用od动态调试
逆向入门 拖入ex发现不是exe文件
把后缀改成txt试试
这是啥???
查了一下
好像是个图片
百度了一下图片的base64编码
Base64编码是一种图片处理格式,通过特定的算法将图片编码成一长串字符串,在页面上显示的时候,可以用该字符串来代替图片的url属性。
base64编码就是长得像下面这样子的代码:
thunder://QUFodHRwOi8vd3d3LmJhaWR1LmNvbS9pbWcvc3NsbTFfbG9nby5naWZaWg==
上面代码大家都熟悉吧,迅雷下载链接哦,就是base64编码后的地址,所以以后看到这种:一堆连续字母,最后有1~2个"="
的代码就是base64。Base64编码并不只是用在图片处理上,还可以用在URL转换上,比如上述我们常见的迅雷以thunder开头的专用地址,就是通过Base64加密处理过后的URL地址。
base64:URL就是URL地址是base64编码的。
例如下面这个:
<img src=”data:image/gif;base64,R0lGODlhAwADAIABAL6+vv///yH5BAEAAAEALAAAAAADAAMAAAIDjA9WADs=” /6>
这个6是我加的,我不加这句话就没了
到在线的base64转图片的网站可转出图片
还有一种方法就是安装上面的格式,前面加
<img src=”
后面加
“/>
然后后缀改成html打开
love 用ex打开,32位c++无壳程序
扔进ida
buuctf xor
可以看到遇见了没见过的函数
直接百度
函数原型:int strncmp(const char* str1, const char* str2, size_t num) 头 文 件:#include <string.h> 返 回 值:(与strncmp相同)str1 = str2 则返回0, str1 > str2 则返回大于0的值, str1 < str2 则返回小于0的值
if()括号中返回0以外的数则为真
!加该函数
这里没太看懂,反正是只要b和global相等就可以,所以global里存储了异或后的字符
除了绿色字体的这部分都要处理出来
1 [ 'f',0xA,'k',0xC,'w','&','O','.','@',0x11,'x',0xD,'Z',';','U',0x11,'p',0x19,'F',0x1F,'v','"','M','#','D',0xE,'g',6,'h',0xF,'G','2','O' ]
isinstance(object, classinfo ) [1]
如果参数object是classinfo的实例,或者object是classinfo类的子类的一个实例, 返回True。如果object不是一个给定类型的的对象, 则返回结果总是False。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 key = [ 'f',0xA,'k',0xC,'w','&','O','.','@',0x11,'x',0xD,'Z',';','U',0x11,'p',0x19,'F',0x1F,'v','"','M','#','D',0xE,'g',6,'h',0xF,'G','2','O' ] flag = "f" x = 0 for i in range(0,len(key)-1): if isinstance(key[i],str): if isinstance(key[i+1],str): x = ord(key[i]) ^ ord(key[i+1]) # key[i],key[i+1]同时为字符串 else: x = ord(key[i]) ^ key[i+1] # key[i]为字符串,key[i+1]为整数 else: if isinstance(key[i+1],str): x = key[i] ^ ord(key[i+1]) # key[i]为整数,key[i+1]为字符串 else: x = key[i] ^ key[i+1] # key[i],key[i+1]同时为整数 flag = flag + chr(x) print(flag)
代码是看的wp,instance函数和strncmp之前没见过
1 flag{QianQiuWanDai_YiTongJiangHu}
hello world 第一次接触安卓逆向
下载了个apkide
将apk文件拖入工具 ctrl+f 搜索main 找到flag
1 flag{7631a988259a00816deda84afb29430a}
re3 拖进ex
无壳32位c++
扔进ida
盲猜一手base64
strcpy 是将右边的字符串赋值给左边
strncpy替代strcpy 来防止缓冲区越界
总之功能差不多
大体逻辑:输入一个字符串,经过base64加密,
将结果赋值给des
des在经过加法
然后与str2对比
str2中存放着处理后的字符
1 2 3 4 5 6 7 import base64 fff="e3nifIH9b_C@n@dH" f="" for i in range(len(fff)): f+=chr(ord(fff[i])-i) print(base64.b64decode(f))
不一样的flag 看不懂哈哈哈
百度了一下
是逆向中的迷宫问题
是个新的知识点
迷宫问题有以下特点:
在内存中布置一张 “地图”
将用户输入限制在少数几个字符范围内.
一般只有一个迷宫入口和一个迷宫出口
布置的地图可以由可显字符 (比如#
和*
)组合而成 (这非常明显, 查看字符串基本就知道这是个迷宫题了.), 也可以单纯用不可显的十六进制值进行表示. 可以将地图直接组成一条非常长的字符串, 或是一行一行分开布置. 如果是一行一行分开布置的话, 因为迷宫一般都会比较大, 所以用于按行(注意, 布置并非按顺序布置, 每行都对应一个具体的行号, 你需要确定行号才能还原迷宫地图) 布置迷宫的函数会明显重复多次.
而被限制的字符通常会是一些方便记忆的组合 (不是也没办法), 比如w/s/a/d
, h/j/k/l
, l/r/u/d
这样的类似组合. 当然各个键具体的操作需要经过分析判断 (像那种只用一条字符串表示迷宫的, 就可以用t
键表示向右移动12
个字符这样). 对于二维的地图, 一般作者都会设置一个X坐标
和一个Y坐标
用于保存当前位置. 我们也可以根据这个特点来入手分析.
一般情况下, 迷宫是只有 1 个入口和 1 个出口, 像入口在最左上角(0, 0)
位置, 而出口在最右下角(max_X, max_Y)
处. 但也有可能是出口在迷宫的正中心, 用一个Y
字符表示等等. 解答迷宫题的条件也是需要根据具体情况判断的.
当然迷宫的走法可能不止 1 条, 也有情况是有多条走法, 但是要求某一个走法比如说代价最小. 那么这就可以变相为一个算法问题.
1 2 3 4 5 6 7 8 9 if ( *(int *)&v3[4 * i + 25] < 0 || *(int *)&v3[4 * i + 25] > 4 ) exit(1); } if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '1' ) exit(1); if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '#' ) { puts("\nok, the order you enter is the flag!"); exit(0);
这两个if语句告诉我们 走到1会失败,走到#会成功
1 *11110100001010000101111#
将该特殊字符串分为5x5
*和#也不能丢
1 2 3 4 5 *1111 01000 01010 00010 1111#
可以用c写个dfs(雾)
发现dfs都不会写了,幸好这个迷宫小
下下下
右右
上上
右右
下下下
结合这个
simplerev strcat 将两个字符串连接
类似于python里的string直接相加
text = (char *)join(key3, v9); 也是字符串相接的一种
快速定位到main函数按f5
发现主要函数
1 2 3 4 5 6 7 8 9 10 11 12 13 *(_QWORD *)src = 'SLCDN'; v7 = 0LL; v8 = 0; v9[0] = 'wodah'; v9[1] = 0LL; v10 = 0; text = (char *)join(key3, v9);//text=killshadow strcpy(key, key1);//key=key1 strcat(key, src);//src=‘ADSFKNDCLS’ v2 = 0; v3 = 0; getchar(); //key3=kills,key1=ADSFK是在stack模块中直接发现的,不用倒过来,src,v9中的值需要注意,x86cpu中存储是小端存储,因此,实际存储的应该是倒过来的
1 2 3 4 5 6 7 8 for ( i = 0; i < v5; ++i ) { if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 ) key[i] = key[v3 % v5] + 32; ++v3; } v3从零开始加,v3一直小于v5,所以v3 % v5就等于v3 这段的作用是如果key中的key数组中ASCII码在64和90之间的字符都加32,实际上就是把key数组中的大写字母全部变成小写字母
1 2 key="ADSFKNDCLS" key.lower()
key=adsfkndcls
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 while ( 1 ) { v1 = getchar(); if ( v1 == '\n' ) break; if ( v1 == ' ' ) { ++v2; } else { if ( v1 <= '`' || v1 > 'z' ) { if ( v1 > '@' && v1 <= 'Z' ) str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97; } else { str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97; } if ( !(v3 % v5) ) putchar(32); ++v2; } }
flag用v1数组进行保存遇到回车键就结束,通过查看asiic🐎可以看出,flag只能是字母组成。将输入的字母进行处理后放入str2数组中
1 2 3 if ( !strcmp(text, str2) ) puts("Congratulation!\n");
要使其经过处理后等于test
1 2 3 4 5 6 7 8 9 key = 'adsfkndcls' flag="" text="killshadow" for i in range(len(text)): for x in range(65,123): if text[i]==chr((x-39-ord(key[i]) + 97) % 26 +97): flag = flag + chr(x) break print('flag{' + flag + '}')
若有一个不对应
直接break
进行下一轮尝试
每一个数都假设为65,123中的一个数
问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 key= "ADSFKNDCLS" key.lower() flag="" text="killshadow" for i in range(len(text)): for x in range(65,123): if text[i]==chr((x-39-ord(key[i]) + 97) % 26 +97): flag = flag + chr(x) break print('flag{' + flag + '}') 第一次把代码写成这样 flag与正确答案相近却不正确 key.lower是返回一个值,不能改变值 应作出如下修改 key=key.lower()
luck_guy
前面过程省略,直接定位到主函数
1 2 3 4 5 6 7 8 9 s=[0x69,0x63,0x75,0x67,0x60,0x6f,0x66,0x7f] flag='GXY{do_not_' for i in range(8): if i%2==1: flag=flag+chr(s[i]-2) else: flag=flag+chr(s[i]-1) print(flag)
GXY{do_not_hate_me}
BJDCTF2020]JustRE 32位无壳
拖进32位ida
发现关键点
尝试提交
错了
猜测%d应该是个具体的数
找到力(╹ڡ╹ )
1 flag{1999902069a45792d233ac}
刮开有奖
还没看答案,我猜是base64
不会做。。
看了看wp,定位到可疑字符串
点两下进不去
交叉引用查询后进入伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) { const char *v4; // esi const char *v5; // edi int v7[2]; // [esp+8h] [ebp-20030h] BYREF int v8; // [esp+10h] [ebp-20028h] int v9; // [esp+14h] [ebp-20024h] int v10; // [esp+18h] [ebp-20020h] int v11; // [esp+1Ch] [ebp-2001Ch] int v12; // [esp+20h] [ebp-20018h] int v13; // [esp+24h] [ebp-20014h] int v14; // [esp+28h] [ebp-20010h] int v15; // [esp+2Ch] [ebp-2000Ch] int v16; // [esp+30h] [ebp-20008h] CHAR String[65536]; // [esp+34h] [ebp-20004h] BYREF char v18[65536]; // [esp+10034h] [ebp-10004h] BYREF if ( a2 == 272 ) return 1; if ( a2 != 273 ) return 0; if ( (_WORD)a3 == 1001 ) { memset(String, 0, 0xFFFFu); GetDlgItemTextA(hDlg, 1000, String, 0xFFFF); if ( strlen(String) == 8 ) { v7[0] = 90; v7[1] = 74; v8 = 83; v9 = 69; v10 = 67; v11 = 97; v12 = 78; v13 = 72; v14 = 51; v15 = 110; v16 = 103; sub_4010F0(v7, 0, 10); memset(v18, 0, 0xFFFFu); v18[0] = String[5]; v18[2] = String[7]; v18[1] = String[6]; v4 = (const char *)sub_401000(v18, strlen(v18)); memset(v18, 0, 0xFFFFu); v18[1] = String[3]; v18[0] = String[2]; v18[2] = String[4]; v5 = (const char *)sub_401000(v18, strlen(v18)); if ( String[0] == v7[0] + 34 && String[1] == v10 && 4 * String[2] - 141 == 3 * v8 && String[3] / 4 == 2 * (v13 / 9) && !strcmp(v4, "ak1w") && !strcmp(v5, "V1Ax") ) { MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0); } } return 0; } if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 ) return 0; EndDialog(hDlg, (unsigned __int16)a3); return 1; }
字符串加密部分
String,应该是我们要的flag,flag = 8.,也就是有8个字符
进入sub_4010F0(v7, 0, 10);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 int __cdecl sub_4010F0(int a1, int a2, int a3) { int result; // eax int i; // esi int v5; // ecx int v6; // edx result = a3; for ( i = a2; i <= a3; a2 = i ) { v5 = 4 * i; v6 = *(_DWORD *)(4 * i + a1); if ( a2 < result && i < result ) { do { if ( v6 > *(_DWORD *)(a1 + 4 * result) ) { if ( i >= result ) break; ++i; *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result); if ( i >= result ) break; while ( *(_DWORD *)(a1 + 4 * i) <= v6 ) { if ( ++i >= result ) goto LABEL_13; } if ( i >= result ) break; v5 = 4 * i; *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1); } --result; } while ( i < result ); } LABEL_13: *(_DWORD *)(a1 + 4 * result) = v6; sub_4010F0(a1, a2, i - 1); result = a3; ++i; } return result; }
要把它转为c语言代码可解出字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <stdio.h> int sub_4010F0(char* a1, int a2, int a3) { int result; // eax int i; // esi int v5; // ecx int v6; // edx result = a3; for ( i = a2; i <= a3; a2 = i ) { v5 = i; v6 = i[a1]; if ( a2 < result && i < result ) { do { if ( v6 > a1[result]) { if ( i >= result ) break; ++i; a1[v5] = a1[result]; if ( i >= result ) break; while ( a1[i] <= v6 ) { if ( ++i >= result ) goto LABEL_13; } if ( i >= result ) break; v5 = i; a1[result] = a1[i]; } --result; } while ( i < result ); } LABEL_13: a1[result] = v6 ; sub_4010F0(a1, a2, i - 1); result = a3; ++i; } return result; } int main() { char str[] = "ZJSECaNH3ng"; sub_4010F0(str,0,10); printf("%s", str); return 0; }
str由上一级的数字转字符串而来
数组的下标有时需要乘以字节数
比如整形a1数组 a1[5]
在伪代码就是
(_DWORD ) 是汇编的表示
代码运行结果:
尝试提交
错了
捏mmd v4v5还有
持续跟进函数
发现base64的标志
推测是将,v4 = ak1w,v5 = V1Ax,两个字符 串base64加密。
加密之后,v4 = jMp,v5 = WP1.
最后,我们看到最后的if语句,
第一句:String[0] == v7[0] + 34,这里的v7【0】,就是上面10个字符的第一个字符,我们通过加密函数之后,v7【0】由一开始的Z变成了,v7【0】 = 3.
3的ASCII码是51,51 + 34 = 85,85ASCII码对应的是大写的 U。flag第一个字符得到。
第二句:String[1] == v10,v10在之前没加密的时候,是排第五位,我们看看加密之后的第五位是谁,3CEHJNSZagn,可以看到,加密之后的第五位是 J。flag第二个字符得到。
第三句:4 * String[2] - 141 == 3 * v8,v8在没加密之前,是排第三位,先看看加密之后的第三位是谁,可以看到是E,E的ASCII码是69,所以3*69 + 141 / 4 = 87 ,ASCII为W,flag第三个字符得到。
第四句:String[3] / 4 == 2 * (v13 / 9),看到v13没加密之前排到数第四位,看看加密之后的到数第四位是谁,是Z,Z的ASCII是90,所以2(90/9) 4 = 80 ,ASCII为P,flag第四个字符得到。
后面四个字符,就是base64加密的那几个,可以看到第三第四字符已经是WP了,说明,WP1在前,jMp在后。
将他们拼接在一起,得到,UJWP1jMp。
带上flag{}
得到
java逆向 用jadx打开
叫“增强for循环 ”,其实就是依此用arr中的字符去代替c中的字符,就是对我们输入的flag进行处理
key是处理后的字符
1 2 3 4 5 6 key = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65] flag="" for i in range(len(key)): flag+=chr((key[i]^32)-ord('@')) print(flag)
注意括号,异或的优先级低于减号
This_is_the_flag_!
简单注册器 apk文件
扔进jadx
关键函数
解题代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 f="dd2940c04462b4dd7c450528835cca15" x=list(f) temp="" x[2]=chr(ord(x[2])+ord(x[3])-50) x[4]=chr(ord(x[2])+ord(x[5])-48) x[30]=chr(ord(x[31])+ord(x[9])-48) x[14]=chr(ord(x[27])+ord(x[28])-97) for i in range(0,16): temp=x[31-i] x[31-i]=x[i] x[i]=temp flag="".join(x) print(flag)
知识点:
1.字符串转列表 x=list(f)
2.列表转字符串 join方法 1 2 3 4 lis = ['1','2','3','4','5'] s = " " .join (lis) print(s) >>>'1 2 3 4 5'
语法格式为: str.join(sequence ) sequence是序列类型,序列类型有列表、元组、range 如果列表中为int型,可使用map(,)
1 2 3 lis = [1,2,3,4,5] s = " ".join(map(str,lis)) print(s) >>>'1 2 3 4 5'
for循环 1 2 3 4 lis = ['1','2','3','4','5'] s = "" for i in lis: s = s + str(i) + " " print(s)
使用 * 号 1 2 3 4 5 a = [1,2,3,4,5] print(a) print(*a) >>>[1,2,3,4,5] >>>1 2 3 4 5
[GWCTF 2019]pyre 后缀名是pyc
python反汇编
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #!/usr/bin/env python # visit https://tool.lu/pyc/ for more information # Version: Python 2.7 print 'Welcome to Re World!' print 'Your input1 is your flag~' l = len(input1) for i in range(l): num = ((input1[i] + i) % 128 + 128) % 128 code += num for i in range(l - 1): code[i] = code[i] ^ code[i + 1] print code code = [ '%1f', '%12', '%1d', '(', '0', '4', '%01', '%06', '%14', '4', ',', '%1b', 'U', '?', 'o', '6', '*', ':', '%01', 'D', ';', '%', '%13']
逆过来就可以
比较简单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 code = [ '%1f', '%12', '%1d', '(', '0', '4', '%01', '%06', '%14', '4', ',', '%1b', 'U', '?', 'o', '6', '*', ':', '%01', 'D', ';', '%', '%13'] l=len(code) for i in range(l-2,-1,-1): code[i]=chr(ord(code[i])^ord(code[i+1]))
草,好像没那么简单
(a+b)%c == (a%c+b%c)%c ((input1[i] + i) % 128 + 128) % 128 = ((input1[i] + i) % 128%128 + 128%128) % 128=(input1[i] + i) %128
???为什么同一个网站我和别人反编译的不一样
%1f 改为\x1f
以此类推
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 code = [ '\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13'] l=len(code) for i in range(l-2,-1,-1): code[i]=chr(ord(code[i]) ^ ord(code[i+1])) for i in range(l): print(chr((ord(code[i])-i)%128),end='')
[ACTF新生赛2020]easyre 有壳
用工具脱掉
c++ 32位程序
代码分析:将v5中的字符串转为ascii码再减一,作为data的索引下标,取出的字符与v4相同
脚本分析:在data数组中find出组成v4的下标,再加1,转成字符,组成flag
1 2 3 4 5 6 7 8 9 10 11 v4 = [42,70,39,34,78,44,34,40,73,63,43,64] flag = '' __data_start__ = '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(\'&%$# !"' #27h 和 ~是由十六进制数转过来的 for i in v4: flag+=chr(__data_start__.find(chr(i))+1) print(flag)
[ACTF新生赛2020]rome 想了好久才想明白,真的老了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 int func() { int result; // eax int v1; // [esp+14h] [ebp-44h] int v2; // [esp+18h] [ebp-40h] int v3; // [esp+1Ch] [ebp-3Ch] int v4; // [esp+20h] [ebp-38h] unsigned __int8 v5; // [esp+24h] [ebp-34h] unsigned __int8 v6; // [esp+25h] [ebp-33h] unsigned __int8 v7; // [esp+26h] [ebp-32h] unsigned __int8 v8; // [esp+27h] [ebp-31h] unsigned __int8 v9; // [esp+28h] [ebp-30h] int v10; // [esp+29h] [ebp-2Fh] int v11; // [esp+2Dh] [ebp-2Bh] int v12; // [esp+31h] [ebp-27h] int v13; // [esp+35h] [ebp-23h] unsigned __int8 v14; // [esp+39h] [ebp-1Fh] char v15; // [esp+3Bh] [ebp-1Dh] char v16; // [esp+3Ch] [ebp-1Ch] char v17; // [esp+3Dh] [ebp-1Bh] char v18; // [esp+3Eh] [ebp-1Ah] char v19; // [esp+3Fh] [ebp-19h] char v20; // [esp+40h] [ebp-18h] char v21; // [esp+41h] [ebp-17h] char v22; // [esp+42h] [ebp-16h] char v23; // [esp+43h] [ebp-15h] char v24; // [esp+44h] [ebp-14h] char v25; // [esp+45h] [ebp-13h] char v26; // [esp+46h] [ebp-12h] char v27; // [esp+47h] [ebp-11h] char v28; // [esp+48h] [ebp-10h] char v29; // [esp+49h] [ebp-Fh] char v30; // [esp+4Ah] [ebp-Eh] char v31; // [esp+4Bh] [ebp-Dh] int i; // [esp+4Ch] [ebp-Ch] v15 = 81; v16 = 115; v17 = 119; v18 = 51; v19 = 115; v20 = 106; v21 = 95; v22 = 108; v23 = 122; v24 = 52; v25 = 95; v26 = 85; v27 = 106; v28 = 119; v29 = 64; v30 = 108; v31 = 0; printf("Please input:"); scanf("%s", &v5); result = v5; if ( v5 == 'A' ) { result = v6; if ( v6 == 'C' ) { result = v7; if ( v7 == 'T' ) { result = v8; if ( v8 == 'F' ) { result = v9; if ( v9 == '{' ) { result = v14; if ( v14 == '}' ) { v1 = v10; v2 = v11; v3 = v12; v4 = v13; for ( i = 0; i <= 15; ++i ) { if ( *((_BYTE *)&v1 + i) > 64 && *((_BYTE *)&v1 + i) <= 90 ) *((_BYTE *)&v1 + i) = (*((char *)&v1 + i) - 51) % 26 + 65; if ( *((_BYTE *)&v1 + i) > 96 && *((_BYTE *)&v1 + i) <= 122 ) *((_BYTE *)&v1 + i) = (*((char *)&v1 + i) - 79) % 26 + 97; } for ( i = 0; i <= 15; ++i ) { result = (unsigned __int8)*(&v15 + i); if ( *((_BYTE *)&v1 + i) != (_BYTE)result ) return result; } result = printf("You are correct!"); } } } } } } return result; } 上面那一串转成字符就是处理后的字符
1 2 3 4 5 6 7 8 9 10 11 12 13 fff="Qsw3sj_lz4_Ujw@l" flag="" for i in range(len(fff)): for n in range(128): j = n if j > 64 and j <= 90: j = (j - 51) % 26 + 65 if j > 96 and j <= 122: j = (j - 79) % 26 + 97 if j == ord(fff[i]): flag = flag + chr(n) print(flag) 直接爆破,如何经过一系列处理能到达fff中的字符就是flag中的字符,是一一对应的
[FlareOn4]login ???
咋是个网页
查看源代码
没见过的算法呢
百度了一下
rot13加密,这种加密应该是属于弱加密吧,就是对原有的ascll值+13或者-13,原理还是很简单
a-m 对应替换为 n-z
n-z 对应替换为 a- m
A-M 对应替换为 N-Z
N-Z 对应替换为A-M
百度在线解密网站
1 clientsideloginsareeasy@flare-on.com
不对。。
大小写不能变
这网站有点问题
1 flag{ClientSideLoginsAreEasy@flare-on.com}
CrackRTF 32位无壳c++
拖进ida
直接定位进main函数
[GUET-CTF2019]re upx壳
脱壳后咋没区别
不会。
好吧,是反汇编的文件没删干净,删了在重新用ida打开
没有main函数
看一下字符串
sub_4009AE函数显然是关键函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 _BOOL8 __fastcall sub_4009AE(char *a1) { if ( 1629056 * *a1 != 166163712 ) return 0LL; if ( 6771600 * a1[1] != 731332800 ) return 0LL; if ( 3682944 * a1[2] != 357245568 ) return 0LL; if ( 10431000 * a1[3] != 1074393000 ) return 0LL; if ( 3977328 * a1[4] != 489211344 ) return 0LL; if ( 5138336 * a1[5] != 518971936 ) return 0LL; if ( 7532250 * a1[7] != 406741500 ) return 0LL; if ( 5551632 * a1[8] != 294236496 ) return 0LL; if ( 3409728 * a1[9] != 177305856 ) return 0LL; if ( 13013670 * a1[10] != 650683500 ) return 0LL; if ( 6088797 * a1[11] != 298351053 ) return 0LL; if ( 7884663 * a1[12] != 386348487 ) return 0LL; if ( 8944053 * a1[13] != 438258597 ) return 0LL; if ( 5198490 * a1[14] != 249527520 ) return 0LL; if ( 4544518 * a1[15] != 445362764 ) return 0LL; if ( 3645600 * a1[17] != 174988800 ) return 0LL; if ( 10115280 * a1[16] != 981182160 ) return 0LL; if ( 9667504 * a1[18] != 493042704 ) return 0LL; if ( 5364450 * a1[19] != 257493600 ) return 0LL; if ( 13464540 * a1[20] != 767478780 ) return 0LL; if ( 5488432 * a1[21] != 312840624 ) return 0LL; if ( 14479500 * a1[22] != 1404511500 ) return 0LL; if ( 6451830 * a1[23] != 316139670 ) return 0LL; if ( 6252576 * a1[24] != 619005024 ) return 0LL; if ( 7763364 * a1[25] != 372641472 ) return 0LL; if ( 7327320 * a1[26] != 373693320 ) return 0LL; if ( 8741520 * a1[27] != 498266640 ) return 0LL; if ( 8871876 * a1[28] != 452465676 ) return 0LL; if ( 4086720 * a1[29] != 208422720 ) return 0LL; if ( 9374400 * a1[30] == 515592000 ) return 5759124 * a1[31] == 719890500; return 0LL; }
注意:6没有
16和17反了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 //python a = [166163712, 731332800, 357245568, 1074393000, 489211344, 518971936, 406741500, 294236496, 177305856, 650683500, 298351053, 386348487, 438258597, 249527520, 445362764, 981182160, 174988800, 493042704, 257493600, 767478780, 312840624, 1404511500, 316139670, 619005024, 372641472, 373693320, 498266640, 452465676, 208422720, 515592000, 719890500] b = [1629056, 6771600, 3682944, 10431000, 3977328, 5138336, 7532250, 5551632, 3409728, 13013670, 6088797, 7884663, 8944053, 5198490, 4544518, 10115280, 3645600, 9667504, 5364450, 13464540, 5488432, 14479500, 6451830, 6252576, 7763364, 7327320, 8741520, 8871876, 4086720, 9374400, 5759124] z = [] for i in range(len(a)): z.append(chr(int(a[i]/b[i]))) print(z[i], end='') print() for i in range(10): s = z[:] s.insert(6, str(i)) print(''.join(s))
第六位直接爆破
1 flag{e165421110ba03099a1c039337}
[2019红帽杯]easyRE 无壳
idapro直接开
无显著main函数
搜索字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 __int64 sub_4009C6() { __int64 result; // rax int i; // [rsp+Ch] [rbp-114h] __int64 v2; // [rsp+10h] [rbp-110h] __int64 v3; // [rsp+18h] [rbp-108h] __int64 v4; // [rsp+20h] [rbp-100h] __int64 v5; // [rsp+28h] [rbp-F8h] __int64 v6; // [rsp+30h] [rbp-F0h] __int64 v7; // [rsp+38h] [rbp-E8h] __int64 v8; // [rsp+40h] [rbp-E0h] __int64 v9; // [rsp+48h] [rbp-D8h] __int64 v10; // [rsp+50h] [rbp-D0h] __int64 v11; // [rsp+58h] [rbp-C8h] char v12[13]; // [rsp+60h] [rbp-C0h] BYREF char v13[4]; // [rsp+6Dh] [rbp-B3h] BYREF char v14[19]; // [rsp+71h] [rbp-AFh] BYREF char v15[32]; // [rsp+90h] [rbp-90h] BYREF int v16; // [rsp+B0h] [rbp-70h] char v17; // [rsp+B4h] [rbp-6Ch] char v18[72]; // [rsp+C0h] [rbp-60h] BYREF unsigned __int64 v19; // [rsp+108h] [rbp-18h] v19 = __readfsqword(0x28u); qmemcpy(v12, "Iodl>Qnb(ocy", 12); v12[12] = 127; qmemcpy(v13, "y.i", 3); v13[3] = 127; qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14)); memset(v15, 0, sizeof(v15)); v16 = 0; v17 = 0; sub_4406E0(0LL, v15, 37LL); v17 = 0; if ( sub_424BA0(v15) == 36 ) { for ( i = 0; i < (unsigned __int64)sub_424BA0(v15); ++i ) { if ( (unsigned __int8)(v15[i] ^ i) != v12[i] ) { result = 4294967294LL; goto LABEL_13; } } sub_410CC0("continue!"); memset(v18, 0, 65); sub_4406E0(0LL, v18, 64LL); v18[39] = 0; if ( sub_424BA0(v18) == 39 ) { v2 = sub_400E44(v18); v3 = sub_400E44(v2); v4 = sub_400E44(v3); v5 = sub_400E44(v4); v6 = sub_400E44(v5); v7 = sub_400E44(v6); v8 = sub_400E44(v7); v9 = sub_400E44(v8); v10 = sub_400E44(v9); v11 = sub_400E44(v10); if ( !(unsigned int)sub_400360(v11, off_6CC090) ) { sub_410CC0("You found me!!!"); sub_410CC0("bye bye~"); } result = 0LL; } else { result = 4294967293LL; } } else { result = 0xFFFFFFFFLL; } LABEL_13: if ( __readfsqword(0x28u) != v19 ) sub_444020(); return result; }
而且发现了base64编码的标志
1 2 3 4 5 6 7 8 9 10 11 if ( sub_424BA0(v15) == 36 ) { for ( i = 0; i < (unsigned __int64)sub_424BA0(v15); ++i ) { if ( (unsigned __int8)(v15[i] ^ i) != v12[i] ) { result = 4294967294LL; goto LABEL_13; } } sub_410CC0("continue!");
关键部分
flag要满足的条件之2就是,v15[i] ^ i == v12[i], v12已经给出
但是具体 i 的范围是0~strlen(v15), 也就是说 0<= i < 36,而v12长度只有13,但是注意到这三个数组是连续存放的,所以再访问的时候应该也是连续访问,所以实际上就是三个数组合在一起成为目标数组。
求v15 长度36
已知v12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 hint = [] str1 = "Iodl>Qnb(ocy" for i in range(len(str1)): hint.append(ord(str1[i])) hint.append(127) str2 = "y.i" for i in range(len(str2)): hint.append(ord(str2[i])) hint.append(127) str3 = "d`3w}wek9{iy=~yL@EC" for i in range(len(str3)): hint.append(ord(str3[i])) str = "" for i in range(len(hint)): str += chr(hint[i] ^ i) print(str)
1 Info:The first four chars are `flag`
flag的前四位是flag
6
关于v12,v13,v14三个数组是连续的, ida动态调试证明一下
我的ida怎么动态调试不了
。。
睡了
明天再看