其实我根本不懂VB,也不喜欢VB这种BEGIN...END的格式,这次也只是帮朋友一个忙,才接触到了VB.
简单描述一下情况:
乔君是做VB开发,需要和手持机一些设备打交道,这中间的纽带是一个名为"abc.dll"的动态链接库程序.现在可以通过个abc.dll读取到ic卡里的数据,但是发现这个ic卡里的数据是加密过的,而这个解决过程就在abc.dll里.现在业务需要要拓展,要二次开发,需要写一些数据到ic卡上,这就难倒了朋友.因为abc上不提供把数据加密后写进去的接口.
这就有了我帮他找到解密的算法,弄清楚算法由他在来处理.通过远程在他的机器上跟踪调试没多少功夫就找到了解密的函数.IDA强大的F5一看,呀呀的,有些懒得逆算法,这事太伤身.当然想愉懒就有了侥幸了想法,强大的IDA每几分钟就帮我找到了他的加密算法,其实abc.dll里提有不少接口函数,只是没有导出.看来是abc.dll在发布的时候故意不太想让人用吧.不管了,有这个加密算法就好了,导出来让vb调用就是了.本来想pediy改改导出表,整整PE,人懒啊,自己定个dll内联一下汇编去调用abc.dll得了,这方法so easy啊.(其实最后找了一工具,直接强制把一些内部函数导出来,不需要手工去改导出表了)
现在重点:
IDA中函数是这样调用的
push edx ; //串口密文 解密后数据也返回在这里
push edi ; //长度
push esi ; // 加解密 Key 数据
call sub_100xxxxx
用C来描述这个函数的声明即 Func(unsigned char *Data,int len,unsigned char *KeyData);
VB中的声明为:
Public Declare Function FuncDeCode Lib "abc.dll" (ByVal cpin As Long, ByVal cpint As Long, ByVal cpkey As Long)
VB的调用部分代码大致为
dim MyData(1 To 10) as byte
dim KeyData(1 To 16) as byte
dim rVal as long
....
rVal=FuncDeCode(VarPtr(MyData(1)),10,VarPtr(KeyData(1)))
执行程序就崩溃了
OD看看
00401E2B . 8B4D 9C mov ecx, dword ptr [ebp-64]
00401E2E . 50 push eax
00401E2F . 6A 18 push 18
00401E31 . 8D55 A0 lea edx, dword ptr [ebp-60]
00401E34 . 51 push ecx
00401E35 . 52 push edx //问题就在这里,明明只有3个参数,为什么这里push了4次
00401E36 . E8 8DFBFFFF call 004019C8 //调用FuncDeCode函数
00401E3B . FF15 14104000 call dword ptr [<&MSVBVM60.__vbaSetSy>; msvbvm60.__vbaSetSystemError
00401E41 . 8D45 A0 lea eax, dword ptr [ebp-60]
00401E44 . 50 push eax
00401E45 . FF15 80104000 call dword ptr [<&MSVBVM60.__vbaI4Var>; msvbvm60.__vbaI4Var
00401E4B . 8D4D A0 lea ecx, dword ptr [ebp-60]
00401E4E . FF15 08104000 call dword ptr [<&MSVBVM60.__vbaFreeV>; msvbvm60.__vbaFreeVar
上面也有注释,很奇怪吧,为什么传了4个参数,我把这里nop掉程序就能正常执行,并得出正确的计算结果.
有没有发现,多余的这个参数,也作了下面一些调用的参数msvbvm60.__vbaI4Var,msvbvm60.__vbaFreeVar
弄了半天也没弄明白怎么回事,直到乔君发给我的一个程序是正常的传递参数的,认真对比,发现导致问题的原因是在VB中声明函数是有问题
Public Declare Function FuncDeCode Lib "abc.dll" (ByVal cpin As Long, ByVal cpint As Long, ByVal cpkey As Long)
修改为
Public Declare Function FuncDeCode Lib "abc.dll" (ByVal cpin As Long, ByVal cpint As Long, ByVal cpkey As Long) As Long
本来这个函数返回值并不重要,因为是指针传的数据,数据加解密调用后就变成了需要的数据,也就没有注意到这里
这个东东,只是为了作个记录而已~
细节很重要!!