此次2024年美亚杯资格赛涉及到的程序逆向不是恶意程序,所以可以直接在真机上运行。看了一些解题思路写得不详细,今日再拿起复盘顺便做个记录,素材及软件链接在文末。
1.在 U盘中,你还发现了一个exe文件,但它被锁定,可能需要进行反编译以便进一步检查。
参考David_USB_8GB.e01,使用x64dbg的字符串搜索(String Search)功能,在Bitlocker.exe中查找哪个字符串最有可能与显示的登录状态有关?
A:Welcome;
B:Invalid input;
C:Login Successful!;
D:Access Denied
答案:C
步骤:
1.使用IDA软件打开Bitlocker.exe
点击File-Open 选择Bitlocker.exe
题干当中提示的是字符串,我们在这时显示程序中出现的字符串可以使用快捷键shift + F12 显示出来,也可在视图(view)->打开子视图(open subviews)->字符串视图(strings)
2.承上題,当找到控制登录成功的逻辑代码时,如何修改汇编代码(Assembly Code)来绕过检查,达到任意输入,都成功登录的效果?
A:修改CMP指令,使其总是比较相等;
B:修改CMP 指令後的跳转指令JNE 為nop,使跳转指令失效;
C:修改MOV指令,使其移动错误的数据;
D:修改TEST 指令後的跳转指令JNE 為nop,使跳转指令失效
答案:
定位到该为止 使用ctrl+x进行交叉引用,定位该代码的位置
步骤:
上图在该位置进行双击,跳转到下图后按ctrl+x进行跳转
lea rdx, String ; "Login Successful!" mov rcx, cs:qword_140008768 ; hWnd call cs:SetWindowTextA movzx eax, cs:byte_14000808C test eax, eax jnz short loc_1400020C5
代码功能概述
这段代码看起来像是在 Windows 环境下(基于调用了 SetWindowTextA
函数来推测)执行的一段汇编代码片段,其主要目的可能是根据某个条件来设置窗口的文本内容,并且后续进行了一个条件判断。
指令分析
1.lea rdx, String ; "Login Successful!"
1.lea
(Load Effective Address)指令在这里用于将 String
的有效地址加载到 rdx
寄存器中。从注释来看,String
大概率指向一个字符串常量 "Login Successful!"
,意味着后续可能会用这个字符串作为参数传递给相关函数(在这里就是 SetWindowTextA
)去设置窗口显示的文本内容。
2.mov rcx, cs:qword_140008768 ; hWnd
1.mov
指令用于数据传送,这里是把段选择符为 cs
(代码段)中偏移地址为 140008768
处的一个 64 位(qword
)数据传送到 rcx
寄存器中。从注释 hWnd
推测,这个地址处存放的应该是一个窗口句柄(hWnd
),而在 Windows API 中,很多函数都需要窗口句柄作为参数来指定操作的目标窗口,SetWindowTextA
就是其中之一,它会对由该句柄指定的窗口进行文本设置操作。
3.call cs:SetWindowTextA
1.call
指令用于调用函数,这里调用的是位于代码段(cs
)中的 SetWindowTextA
函数,并且通过前面两条指令已经将函数所需要的两个关键参数准备好了,分别放在 rcx
(窗口句柄 hWnd
)和 rdx
(要设置的字符串地址 "Login Successful!"
)寄存器中。SetWindowTextA
函数的作用就是改变指定窗口的标题栏文本或者窗口内文本内容(取决于窗口类型等因素)。
4.movzx eax, cs:byte_14000808C
1.movzx
指令是零扩展传送指令,它会将指定内存位置(这里是代码段中偏移地址为 14000808C
处的字节数据)传送到 eax
寄存器中,并将高字节(因为 eax
是 32 位寄存器,而源操作数是字节)用零进行扩展填充。
5.test eax, eax
1.test
指令用于执行逻辑与操作,但不保存结果,只根据结果设置标志位(如 ZF
零标志位等)。在这里它对 eax
寄存器自身进行逻辑与操作,实际目的通常是用来检查 eax
寄存器的值是否为零。例如,如果 eax
为零,那么 ZF
(零标志位)会被置 1
;如果 eax
不为零,ZF
则为 0
。
6.jnz short loc_1400020C5
1.jnz
(Jump if Not Zero)是条件跳转指令,它会根据前面 test
指令设置的标志位情况来决定是否跳转。如果 ZF
标志位为 0
(即 eax
不为零),那么程序就会跳转到偏移地址为 1400020C5
的位置(标记为 loc_1400020C5
处)继续执行后续代码;如果 ZF
为 1
(即 eax
等于零),则会按顺序执行紧跟在这条指令后面的代码(前提是没有其他跳转等改变执行流程的情况出现)。
总体而言,这段代码先是尝试设置窗口文本内容,然后检查一个字节变量的值,根据其是否为零来决定下一步的执行流程(跳转到指定位置或者顺序执行后续代码)。具体完整的功能还需要结合更多的上下文代码以及程序的整体逻辑来综合判断。
3.参考David_USB_8GB.e01,Bitlocker.exe的正确用户登录名称是?
答案:david1337
步骤:上述是判断是否登录成功的流程图,所以往上看可以看到其登录逻辑,
通过上一题定位到判断成功失败的位置,在IDA中可以看到该位置前面的流程图存在两个字符串,使用字符串:” david1337”作为用户登入名称,字符串:” 1337david”作为登入密码进行登入,提示Login Successful!。
通过 lea
指令获取 String
的地址和一个字符串常量 "david1337"
的地址
4.参考David_USB_8GB.e01,Bitlocker.exe的正确登录密码是?
答案:1337david
步骤:如上题。
5.参考David_USB_8GB.e01,当Bitlocker.exe程序尝试显示登录结果(成功或失败)时,使用了哪一种途径来决定显示的消息?
A:通过检查某个寄存器的值来决定跳转到不同的汇编代码区段;
B:通过调用硬编码的内存地址来显示特定的消息框;
C:通过堆栈中的返回地址来确定要显示的消息;
D:通过逐位操作来修改显示消息的字符串内容
答案:A
解题思路:见第二题题解。
6.参考David_USB_8GB.e01,决定能否解密 Bitlocker Key 的字节的内存偏移量(Memory Offset)(相对于基址"bitlocker.exe")是什么?
A:0xA0B2;
B:0x808C;
C:0xA0C8;
D:0xA0E0
解题步骤:
{
SetWindowTextA(qword_140008768, "Login Successful!");
if ( !byte_14000808C )
MessageBoxA(
0i64,
"Great! You have finished the first step. Keep going to find the bitlocker key.",
"login successful",
0);
if ( byte_14000808C )
{
sub_1400022A0(v24, v23, v22);
v10 = (const CHAR *)sub_1400029E0(v24);
MessageBoxA(0i64, v10, "The Bitlocker Key", 0);
sub_140002B40(v24);
}
}
sub_140002B40(v25);
sub_140002790(v22);
return sub_140002790(v23);
}
(“14000”为当前基址,所以选项表述0x808C)
1.if (!byte_14000808C )
及相关 MessageBoxA
调用
1.首先进行了一个条件判断,检查 byte_14000808C
的值是否为零(通过 !
取反操作来判断其是否为假,即值为零)。如果 byte_14000808C
的值为零,就会执行下面的 MessageBoxA
函数调用。
2.MessageBoxA
函数同样是 Windows API 函数,用于弹出一个消息框与用户进行交互。这里弹出的消息框标题为 "login successful"
,内容为 "Great! You have finished the first step. Keep going to find the bitlocker key."
,并且父窗口句柄参数设置为 0i64
(可能表示无父窗口或者是基于特定的默认设置),最后一个参数 0
可能是用于指定消息框的样式等相关属性(具体取决于 MessageBoxA
函数的参数定义和使用约定)。这个消息框主要是向用户提示已经完成了第一步操作,并鼓励继续去查找 Bitlocker 密钥相关内容。
2.if ( byte_14000808C )
及相关函数调用
1.当 byte_14000808C
的值不为零(即条件判断为真)时,会依次执行以下操作:
1.sub_1400022A0(v24, v23, v22);
:调用自定义的函数 sub_1400022A0
,并传入 v24
、v23
、v22
这几个参数,具体该函数的功能取决于其内部实现,从上下文推测可能是为了后续获取 Bitlocker 密钥等操作做准备工作。
2.v10 = (const CHAR *)sub_1400029E0(v24);
:调用 sub_1400029E0
函数,传入 v24
参数,并且将返回值强制转换为 const CHAR *
类型后赋值给 v10
。这个函数很可能是用于获取 Bitlocker 密钥相关的字符串表示或者其他关键信息,返回的结果后续会作为参数传递给 MessageBoxA
函数。
3.MessageBoxA(0i64, v10, "The Bitlocker Key", 0);
:再次调用 MessageBoxA
函数,弹出一个标题为 "The Bitlocker Key"
的消息框,消息框的内容则是由前面获取到的 v10
所指向的字符串(也就是 sub_1400029E0
函数返回的内容),同样父窗口句柄参数为 0i64
,最后一个参数为 0
用于指定消息框样式等属性。这个消息框用于向用户展示获取到的 Bitlocker 密钥相关信息。
4.sub_140002B40(v24);
:调用 sub_140002B40
函数,传入 v24
参数,其功能可能是对之前使用的相关数据进行清理、释放资源或者进行其他与业务逻辑相关的后置处理操作。
或者使用alt+t快捷键进行搜索只有808C能够被搜索到
7.参考David_USB_8GB.e01,决定能否解密 Bitlocker Key 的内存偏移量(Memory Offset)后,应该如何利用它来进行解密?
A:将该偏移量处的值改为 1 (true),以启用解密过程;
B:将该偏移量处的值改为 0 (false),以重新初始化加密过程;
C:将该偏移量的内容保存到档中以作解密过程中的key;
D:清空该偏移量的内存并强制退出程序
答案:A
解题思路:
逆向注入,把byte_14000808C值改为1,然后输入密码,解析出来。
这题需要用ida软件和x64debug软件结合
大致的步骤是将ida的基址改为与x64debug的基址统一,为的是方便定位在x64debug当中的位置,然后将值进行修改。
1.将ida的基址进行修改
在x64dbug软件中选择“符号”,选择bitlocker.exe复制基址
在ida中修改与其相同的基址
点击ok即可
修改完成后再按F5键 显示C伪代码
接下来在x64debug当中跳转到该地址。或者按快捷键ctrl+G
因为是byte类型,将其值改为1
修改完成后再点击左上角运行
如果运行不能正常运行有卡住的情况,可以在设置中将系统断点去掉 如下图
再次运行,输入账号密码即可成功运行。
但此题与U盘恢复出来的图片内容当中的恢复密钥值是一致的
通过网盘分享的文件:2024美亚杯资格赛程序逆向
链接: https://pan.baidu.com/s/1TybTYO-yYldNpiVwV0qatQ?pwd=vdf2 提取码: vdf2
--来自百度网盘超级会员v7的分享