逆向QBasic7.1笔记
一、前言
最近接触了一个QBasic编写的16位程序的逆向,该程序是运行在纯DOS环境下,虽然此环境已离我们远去,能接触到的机会不是太多,但为了防止有意外碰到的同学像我最开始那样走弯路,特此将该笔记整理一下发出,希望对需要的同学有些帮助.由于时间仓促,研究不深文中难免有错误之处,欢迎各高手指教.
QBasic7.1是微软公司推出的一套基于Basic语言的集成开发环境,虽然在当时来说此开发环境功能已经非常强大,但相对于现如今我们这些用惯了Visual Studio, Eclipse等更加强大的人来说,那个环境就有点太老土了.因此我们得换一套更有效率的环境,我用的是SlickEdit 15.0.0.5,至于编译我写了一个简单的批处理来完成.
注: 由于在不同的编译参数下可能会生成不同的程序结构,因此本文只讨论如下参数生成的程序
BC test.bas/V/D/O/FPi/G2/Ot/Lr/Fs/Zi/T/C:512;
其它的差别不大,同学们可以自己研究下 J
二、必要的结构
1: QBasic程序的结构
程序由多个SEGMENT组成,具体结构如下:
注1:用IDA打开目标EXEà”CTRL+E”à选择”入口点”,此时将停在”启动代码”处.
注2:按编译链接时的顺序每个OBJ文件对应一个SEGMENT
2: BAS源文件所在SEGMENT的结构:
上图中的”BAS源文件”对应若干个SEGMENT(取决于有多少个OBJ文件),而每个SEGMENT都是如下的一个结构:
这个”SegHdr”是个管理结构,范围是当前段(SEGMENT),大小为30H.
该结构包含了对应的BAS文件的文件名,各个数据段的偏移等.
每个BAS文件在链接后对应着程序中的一个SEGMENT,段头的前10个字节就是该文件的文件名.这些SEGMENT是按编译顺序排放的.之所以这里会是10个字节因为每个名字都有一个”bl”前缀.
在所有的OBJ合并到EXE中之后,这些段名是不见的,它们都变成了同一个段中的不同偏移位置.
3: 代码结构
每一个SEGMENT的真正代码都是从30H处开始,大致结构如下:
由上图可以看出,所有写在SUB/FUNCTION中的函数都会被这些JMP指令路过.
而那些没写在任何SUB/FUNCTION块中的代码将被执行.也就是QBasic中没一个像C语言那样的main()函数.
三、开始逆向
关于结构方面的东西介绍完了,下面再来看一下跟逆向有实质性关联的东西吧.
1: 参数传递与调用方式
QBasic函数的参数是从左向右压栈的.由本函数负责清理.
参数默认情况下是通过引用传递的,所以在函数内部修改参数值是会影响到外面的.
如:CALL TestSub(1, 2, 3)将会生成如下代码
mov word ptr [bp - 14h], 1
mov word ptr [bp - 16h], 2
mov word ptr [bp - 18h], 3
lea ax, [bp-14h]
push ax
lea ax, [bp-16h]
push ax
lea ax, [bp -18h]
push ax
call TestSub
如果要进行传值调用需要在函数声明时添加BYVAL 说明.
2: 识别库函数
这个可以说是整个逆向过程中最重要的一步了,如果库函数无法识别工作量将会扩大N倍.
但由于IDA本身没有带QBasic的符号,所以在开工之前需要把QB安装目录中的库文件做成
SIG符号文件.记得保留那些中间(PAT)文件,防止IDA不能自动识别时用来手动识别.
具体的制作方法可以去网上搜下教程,这里就不讨论了.
3: 库函数的转换
在QBasic中库函数的名字一般都有个前缀”B$”以此来防止与正常的函数重名.因此即使完成了库函数识别也无法开始工作,还得做一步额外的工作:库函数到接口函数的转换.
这个工作是由编译器在编译时完成的,现在我们反过来操作难度有点大,但好在QBasic的库函数也不是很多,我用了一个比较土的方法:在Google中搜索BAS文件以及相应的OBJ文件并加以人肉分析对比,这样便可以建立起一个对应表, 如:
B$GOSA============= GOSUB SubName
B$FCHR============= CHR$(n)
B$SAS1============== FileName& = "xxxxxxx"
B$PEI2 ============== PRINT x%
B$PSSD============== PRINT "xxxxxxxx";
B$SSHL============== SHELL "xxxxx"
………………….
(限于篇幅有限,就不贴完整的了)
4: 对于READ处理
QBasic中READ和DATA是相对出现的,DATA用来定义一个数据集,而READ则从这些数据集中取出数据给变量赋值.如:
DATA AAA, BBB, CCC, DDD, EEE
FOR I = 0 TO 4
READ KKK$
PRINT KKK$
NEXT I
与之对应的部分汇编代码如下:
…….
push ds
push offset kkk
xor ax, ax
push ax
call B$RDSD ==== READ
push offset kkk
call B$PESD ==== PRINT
……..
这里, DATA去哪了呢?
嗯….来到该代码所在的SegHdr部分,那个Off2指向的区域(即BC_DS段)就包含了这些DATA数据.
5: 需要注意的地方
1)这里特别需要注意的就是QBasic中变量在使用前可以不用声明,因此如果出现如下代码,编译器也不会报错,但结果就大不一样了:
var10 = 1: var12 = 2: var14 = 3: var16 = 4
CALL TestSub(var10, var13, var14, var16)
这里由于手误将”var12”写成了”var13”编译器是发现不了的.
2)所有函数在调用之前都应该声明,否则会被当成数组或变量.
至此都已经差不多了,剩下的都是些体力活了~
四、致谢
在此期间收到了很多的朋友的帮助与技术支持,特别要感谢Pete’s的burger2227与qb_liu.
本文欢迎转载,但请保证信息完整.如有不清楚的欢迎讨论.
thinkSJ (于南京)
五、参考资料
1: PC Magazine's BASIC Techniques and Utilities by Ethan Winer
http://www.ethanwiner.com
2: Pete's QBASIC Site
http://www.petesqbsite.com
3: QB CULT MAGAZINE
http://qbcm.hybd.net
逆向QBasic7.1笔记相关推荐
- 滴水逆向win32学习笔记1
滴水逆向win32学习笔记 一.字符编码 基本介绍 关于utf-16.utf-8和unicode的关系 BOM头 二.宽字符 基本介绍 常用函数 三.Win32 API中的宽字符 什么是win32 A ...
- OD逆向调试程序的笔记
1-读取文本框内容常用的函数(这里的"A"表示ASCII,"W"表示宽字符UNICODE,下同) -GetDlgItemTextA()<这个函数是最常 ...
- 滴水逆向3期笔记与作业——01汇编
防止OneNote丢失. 海哥牛逼. 01汇编笔记 01进制 进制定义 10-2进制转换 八进制 02数据宽度/逻辑运算 数据宽度与存储 逻辑运算 计算机做加法的本质 作业 03通用寄存器_内存读写 ...
- 180728 逆向-SMC出题笔记
在某黑哥的指示下给他加紧出两个题目~ 最先想到的就是34c3ctf时做过的SMC题目,那个随机数混杂着自解密真的是让我久久无法忘怀 SMC题目的核心就在于自解密时的key 如果key不提供,那么考点就 ...
- 静态链接库,动态链接库【滴水逆向三期48笔记】
在开发过程中,我们通常会有很多函数,需要多次使用或在不同的程序中使用该函数,也有可能我们会将我们写好的函数给别人使用,但是我们又不想给他源代码,毕竟代码是我们花了很多功夫写出来的,那么我们如何不发给其 ...
- IAT表入门简析【滴水逆向三期52笔记】
在讲IAT表之前,我们来回忆一下之前学习的知识: 如果我们将函数写在程序的源文件中,那么该函数就会被编译器直接编译到程序的二进制文件中,在程序调用该函数的时候,E8后跟的地址是直接写死的,程序直接在e ...
- 导入表解析,IAT表解析【滴水逆向三期53笔记】
我们再上一章节简要介绍了IAT表,我们知道如果程序调用dll中的函数时,必须通过IAT表来找到函数,我们基本了解了IAT表之后,我们今天来讲解一下导入表,通过本章节的学习,我们可以了解导入表,也能对I ...
- android studio 修改包名_android逆向笔记之初学者常用adb命令
android逆向常用命令笔记 1.如何导出已安装apk? a.列出已经安装的包 | grep -i 关键字 b.找出安装路径 adb shell pm path 包名 c.拉下来: adb pull ...
- adb命令 android 串口_android逆向笔记之初学者常用adb命令
android逆向常用命令笔记 1.如何导出已安装apk? a.列出已经安装的包 adb shell pm list package | grep -i 关键字 b.找出安装路径 adb shell ...
最新文章
- SAP MM MIGO界面里的'Delivery completed'标记
- dubbo 源码编译记录
- 离线安装Cloudera Manager 5和CDH5(最新版5.9.3) 完全教程(七)界面安装
- ubuntu无线网络开关
- Linux下多线程模拟停车场停车
- AWS CEO Andy Jassy 专访:我们一直思考的是未来 2-5 年的事 | 人物志
- (STL,set)安迪的第一个字典
- 关于心理的二十五种倾向(查理#183;芒格)-2
- mysql workbench首页_MySQL Workbench是干什么的?
- KL散度、JS散度以及交叉熵对比
- Day10--路由嵌套+项目前后台搭建
- C语言实现线性回归求斜率
- 年末大盘点 2008十大最受欢迎的装机软件
- ubuntu离线安装免费版本Typora
- 【办公必备软件】万彩办公大师教程丨PDF转HTML工具
- Gentoo虚拟机安装--基于分发内核
- java列表末尾添加元素_在迭代它时将元素添加到Java LinkedList的末尾
- 濒临死亡的校园BBS
- 编辑距离WER/CER计算的一种python实现
- can总线不加末端电阻_高手写的CAN总线入门总结,对全面理解CAN总线特性很有帮助...
热门文章
- 电商平台API接口,店铺所有商品
- LNMP详解(七)——Nginx反向代理配置实战
- android自定义view圆环,Android自定义View实现圆环进度条
- 牛客小白月赛6 J 洋灰三角
- python 自动编写新闻_Python多篇新闻自动采集
- 路由器密码 $1$$zdlNHiCDxYDfeF4MZL.H3/
- 工地wifi认证登录哪里有
- 质监局监督检测指挥系统
- 异常:calling prepareStatement is no longer allowed! Increase reapTimeout to avoid this problem
- html游戏社区豳风破斧,诗经·豳风——《破斧》