-
-
[原创]一次简单的powerbuilder逆向及修改
-
发表于: 2022-11-10 10:30 1622
-
感谢坛友的工具PbdViewer v0.1,另外还用到了PowerBuilder-decompile
单位某系统因为等保整改要求改了数据库密码,结果导致为其定制的数据传输工具无法工作,乙方则因开发离职和交接问题也无法提供支援,只好尝试自己搞了。
打开工具对应ini配置文件,里面对应连接串部分只有两行对应服务器地址和数据库名称:
1 2 3 | [database] SERVERNAME = 192.168 . 3.3 DATABASE = cw30 |
工具目录下有七八个pbd文件,先用hex编辑器逐个打开搜索关键词(ini文件名,及SERVERNAME变量名),找到后再用PbdViewer 逐个打开查看,很快定位到main.pbd文件下的函数:
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 | / / public function integer gf_connect_cw() string ls_dbname string ls_server string ls_err string ls_current_directory string ls_accfile nvo_public_function iuo_pub gtr_cw = create transaction disconnect using gtr_cw; ls_current_directory = iuo_pub.uf_directory_getcurrent() if not fileexists(ls_current_directory + "\CONN.INI" ) then messagebox( "msg: " ,ls_current_directory + "\CONN.INI not exist" ,information!) return - 1 end if ls_accfile = ls_current_directory + "\CONN.INI" ls_dbname = profilestring(ls_accfile, "database" , "DATABASE" ,"") ls_server = profilestring(ls_accfile, "database" , "SERVERNAME" ,"") if ls_dbname <> "" then gtr_cw.dbms = "OLE DB" gtr_cw.servername = ls_server gtr_cw.database = ls_dbname gtr_cw.logid = "cw_" + ls_dbname gtr_cw.logpass = ls_dbname gtr_cw.autocommit = false gtr_cw.dbparm = "PROVIDER='SQLOLEDB',DATASOURCE='" + ls_server + "',PROVIDERSTRING='database=" + ls_dbname + "'" gtr_cw.lock = "RC" connect using gtr_cw; if gtr_cw.sqlcode <> 0 then messagebox( "msg" , "connecting database error" + ls_dbname + ",Error:~r~n" + ls_err + "~r" + left(gtr_cw.sqlerrtext, len (gtr_cw.sqlerrtext) - 1 )) return - 1 end if end if return 1 return |
可以看到连接串部分用库名+固定前缀用作用户名,库名本身就是密码,所以改密码之后就无法连接了。如果有源码的话,就可以在ini配置文件里加上用户密码项,然后修改函数里读文件的部分来读取用户密码。
不过现在只能想别的办法,比如用hex工具直接修改pbd文件伪码。如果只是删改比较简单,但现在直观的办法是要添加变量并赋值,按以前逆asm的经验这需要在代码区和数据区找到空余并添加内容,这对第一次面对powerbuilder的我来说实在有点困难。瞪着代码思考良久的我突然灵光一闪,既然只改了密码,那干脆用配置文件里SERVERNAME项来放密码不就行了吗,至于数据库地址,可以在hosts里把密码绑上目标IP啊(幸好新密码只有数字+大小写字母)!于是接下来的事就非常简单了。
修改ini文件:
1 2 3 | [database] SERVERNAME = nUPaSsw0Rd DATABASE = cw30 |
host文件添加:
1 | 192.168 . 3.3 nUPaSsw0Rd |
接下来只需要把函数里
1 | gtr_cw.logpass = ls_dbname |
改成
1 | gtr_cw.logpass = ls_server |
此时就用到了另一个工具PowerBuilder-decompile,先将pbd文件dump一下:
1 | pbd_dump.py main.pbd |
在输出的一大堆文件里找到函数对应文件gf_connect_cw.fun,再进一步解析该文件:
1 | analyse.py main - pbd\gf_connect_cw.fun |
接下来就能获得gf_connect_cw.code和gf_connect_cw.debug两个文件了,前者基本等同PbdViewer解析出的源码,后者就是对应的伪码,两个文件里有行号可以对应。
源码gf_connect_cw.code里面丢了变量名,不过影响不大
1 2 3 4 | 23 : gtr_zw.:string = ls_server 24 : gtr_zw.:string = ls_dbname 25 : gtr_zw.:string = "cw_" + ls_dbname 26 : gtr_zw.:string = ls_dbname |
伪码gf_connect_cw.debug
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 | line 23 : SM_PUSH_LOCAL_GLOBREF ( 16 ) SM_PUSH_CONST_REF ( 256 , 0 ) SM_DOT_LV ( 2 ) SM_PUSH_LOCAL_VAR ( 1 ) SM_COPY_LVALUE_STRING ( 1 ) SM_ASSIGN_STRING ( 2 ) line 24 : SM_PUSH_LOCAL_GLOBREF ( 16 ) SM_PUSH_CONST_REF ( 264 , 0 ) SM_DOT_LV ( 2 ) SM_PUSH_LOCAL_VAR ( 0 ) SM_COPY_LVALUE_STRING ( 1 ) SM_ASSIGN_STRING ( 2 ) line 25 : SM_PUSH_LOCAL_GLOBREF ( 16 ) SM_PUSH_CONST_REF ( 272 , 0 ) SM_DOT_LV ( 2 ) SM_PUSH_CONST_STRING ( 280 , 0 ) SM_PUSH_LOCAL_VAR ( 0 ) SM_CAT_STRING () SM_POP_POP () SM_ASSIGN_STRING ( 2 ) line 26 : SM_PUSH_LOCAL_GLOBREF ( 16 ) SM_PUSH_CONST_REF ( 288 , 0 ) SM_DOT_LV ( 2 ) SM_PUSH_LOCAL_VAR ( 0 ) SM_COPY_LVALUE_STRING ( 1 ) SM_ASSIGN_STRING ( 2 ) |
现在我们要把行26的 gtr_cw.logpass = ls_dbname 改成 gtr_cw.logpass = ls_server,对比下行23和行24的伪码,SM_PUSH_LOCAL_VAR 这里貌似就是赋值的关键了,大概只要把行26的SM_PUSH_LOCAL_VAR (0) 改成SM_PUSH_LOCAL_VAR (1)就行了。
接下来就是找到伪码对应的hex值,在PowerBuilder-decompile里的pcode.py可以直接查到
1 2 3 4 5 6 | { 'index' : 0x20 , 'name' : 'SM_PUSH_CONST_REF' , 'arg_num' : 2 , 'unknown' : 0x1 , 'addr' : 0x10d54b00 , 'func' : pb_push_const}, { 'index' : 0x2f , 'name' : 'SM_PUSH_LOCAL_GLOBREF' , 'arg_num' : 1 , 'unknown' : 0x1 , 'addr' : 0x10d55100 , 'func' : pb_push}, { 'index' : 0x122 , 'name' : 'SM_DOT_LV' , 'arg_num' : 1 , 'unknown' : 0xffffffff , 'addr' : 0x10d57200 , 'func' : pb_dot}, { 'index' : 0x1e , 'name' : 'SM_PUSH_LOCAL_VAR' , 'arg_num' : 1 , 'unknown' : 0x1 , 'addr' : 0x10d54650 , 'func' : pb_push}, { 'index' : 0x139 , 'name' : 'SM_COPY_LVALUE_STRING' , 'arg_num' : 1 , 'unknown' : 0x0 , 'addr' : 0x10d59cf0 , 'func' : pb_empty}, { 'index' : 0x88 , 'name' : 'SM_ASSIGN_STRING' , 'arg_num' : 1 , 'unknown' : 0xfffffffe , 'addr' : 0x10d4d0b0 , 'func' : pb_assign}, |
伪码操作数长度都是word,行26对应的完整hex就应该是
1 2 | 0000081ah : 2F 00 10 00 20 00 20 01 00 00 22 01 02 00 1E 00 ; 0000082ah : 00 00 39 01 01 00 88 00 02 00 ; |
把SM_PUSH_LOCAL_VAR (0)改成(1),对应的hex就是1E 00 00 00 改成1E 00 01 00
最后用hex工具打开main.pbd,搜索
2F 00 10 00 20 00 20 01 00 00 22 01 02 00 1E 00 00 00 39 01 01 00 88 00 02 00
替换
2F 00 10 00 20 00 20 01 00 00 22 01 02 00 1E 00 01 00 39 01 01 00 88 00 02 00
保存后用PbdViewer 打开验证,函数内代码变成了
1 2 3 4 | gtr_cw.servername = ls_server gtr_cw.database = ls_dbname gtr_cw.logid = "cw_" + ls_dbname gtr_cw.logpass = ls_server |
执行main.exe文件,数据库连通,数据传输功能ok,工作完成!
既没有混淆也没有加壳就还蛮简单的