CB 调用 VC 的DLL 出错

爱蹄子的羊头 2013-01-31 09:03:09
接口头文件


#include <string>

typedef unsigned int uint;


struct IMpkManip
{
virtual void release() = 0;
virtual bool addFile(const char* sourceFilename,const char* targetFilename,bool replaceExist = true,bool compress = true,bool encrypt =false) = 0;

};

extern "C" __declspec(dllexport) IMpkManip* createMpkManip();



然后我在 VC 里面调用这个DLL 正常


#include "IMpkManip.h"
#include <windows.h>
#include <stdlib.h>

using namespace std;
int main()
{
HMODULE pDll = LoadLibrary("Base.dll");
typedef IMpkManip* (*CREATEMPKMANIP)();
CREATEMPKMANIP pShowDlg = (CREATEMPKMANIP)GetProcAddress(pDll,"createMpkManip");
IMpkManip* wwManip = pShowDlg();
wwManip->addFile("c:\\1.txt","1.txt",true,true,false);
system("pause");
return 0;
}



在 C++Builder 里面调用就不正常.


#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include "IMpkManip.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE pDll = LoadLibrary("Base.dll");
typedef IMpkManip* (*CREATEMPKMANIP)();
CREATEMPKMANIP pShowDlg = (CREATEMPKMANIP)GetProcAddress(pDll,"createMpkManip");
IMpkManip* wwManip = pShowDlg();
wwManip->addFile("c:\\1.txt","1.txt",true,true,false);
system("pause");
return 0;
}



为什么啊??
...全文
327 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
爱蹄子的羊头 2013-02-17
  • 打赏
  • 举报
回复
引用 16 楼 zcchm 的回复:
引用 1 楼 warrially 的回复:在 OllyDbg 里面下断点后发现 VC 调用的参数是正常的 C++Builder 调用的 ("c:\\1.txt") 变成了第二个参数 // 是调用约定的问题吗? 应该都是 cdecl才对啊? 不管VC还是CB,他们都是第二个参数,第一个是this。
谢谢大神. 这个 EAX 确实是 this. 但是现在有没有什么办法解决?
zcchm 2013-02-17
  • 打赏
  • 举报
回复
补充,不同编译器类成员内存布局可能是不同的。
zcchm 2013-02-17
  • 打赏
  • 举报
回复
跨编译器dll,不要使用类、虚函数。如果你非要这么做,可以做成com。 不同编译器,类成员的内存布局是不同的,虚函数table实现也不一样。 一般,dll尽可能只使用基本类型作为参数。
zcchm 2013-02-16
  • 打赏
  • 举报
回复
引用 1 楼 warrially 的回复:
在 OllyDbg 里面下断点后发现 VC 调用的参数是正常的 C++Builder 调用的 ("c:\\1.txt") 变成了第二个参数 // 是调用约定的问题吗? 应该都是 cdecl才对啊?
不管VC还是CB,他们都是第二个参数,第一个是this。
zcchm 2013-02-16
  • 打赏
  • 举报
回复
总之,不要这么玩。
zcchm 2013-02-16
  • 打赏
  • 举报
回复
引用 10 楼 dataxdata 的回复:
引用 9 楼 warrially 的回复:输出函数略多了些. 我在汇编里面看C++Builder 多压了一个参数进去. 不知道他为什么要这么做. VC 里面是 push5次 CB push5次以后 又push 了一次 eax 这个好像是控制不了的,可能与COFF转OMF的过程有关,所以现在我已经打算放弃CB了,还是用VC省心
首先确定调用约定,VC demo里是this call,this指针通过ecx传递,其他参数通过堆栈由右向左传递,函数返回时,由被调用函数负责恢复堆栈;CB demo里是__cdecl,所有参数通过堆栈由右向左传递,函数返回时,由调用函数负责恢复堆栈。 这就能解释为什么你看到VC里push 5次,CB里push 6次(最后一次push eax是传递IMpkManip this指针)。
sololie 2013-02-10
  • 打赏
  • 举报
回复
引用
输出函数略多了些. 我在汇编里面看C++Builder 多压了一个参数进去. 不知道他为什么要这么做. VC 里面是 push5次 CB push5次以后 又push 了一次 eax
俺也好奇,它返回前调用了 [[eax]+$28],跟踪看看这个eax是啥对象,到底干了啥
周药师 2013-02-05
  • 打赏
  • 举报
回复
参考下我这里的, http://blog.csdn.net/zhouzhangkui/article/details/5815797 你的问题 可能主要出在 _declspec(dllexport) 、__stdcall 等约定上 仔细检查下
爱蹄子的羊头 2013-02-01
  • 打赏
  • 举报
回复
引用 10 楼 dataxdata 的回复:
引用 9 楼 warrially 的回复:输出函数略多了些. 我在汇编里面看C++Builder 多压了一个参数进去. 不知道他为什么要这么做. VC 里面是 push5次 CB push5次以后 又push 了一次 eax 这个好像是控制不了的,可能与COFF转OMF的过程有关,所以现在我已经打算放弃CB了,还是用VC省心
要做个 工具. MFC 用起来恶心.. 想用 VCL.
dataxdata 2013-02-01
  • 打赏
  • 举报
回复
引用 9 楼 warrially 的回复:
输出函数略多了些. 我在汇编里面看C++Builder 多压了一个参数进去. 不知道他为什么要这么做. VC 里面是 push5次 CB push5次以后 又push 了一次 eax
这个好像是控制不了的,可能与COFF转OMF的过程有关,所以现在我已经打算放弃CB了,还是用VC省心
爱蹄子的羊头 2013-02-01
  • 打赏
  • 举报
回复
引用 8 楼 dataxdata 的回复:
引用 6 楼 warrially 的回复:引用 5 楼 dataxdata 的回复:CB有时就出这样的问题,不行就再用一个DLL封装一下 这个方法可以. 不过已经是下下策了.. 有没有更好的解决办法啊? 我也碰到过几次这样的事情,都是自己用VC再做个DLL重新封装,也不是很麻烦,如果原DLL的输出函数很多很复杂的话,可以把一部分业务逻辑也封装进去,简化调用接……
输出函数略多了些. 我在汇编里面看C++Builder 多压了一个参数进去. 不知道他为什么要这么做. VC 里面是 push5次 CB push5次以后 又push 了一次 eax
dataxdata 2013-02-01
  • 打赏
  • 举报
回复
引用 6 楼 warrially 的回复:
引用 5 楼 dataxdata 的回复:CB有时就出这样的问题,不行就再用一个DLL封装一下 这个方法可以. 不过已经是下下策了.. 有没有更好的解决办法啊?
我也碰到过几次这样的事情,都是自己用VC再做个DLL重新封装,也不是很麻烦,如果原DLL的输出函数很多很复杂的话,可以把一部分业务逻辑也封装进去,简化调用接口;如果简单的话,就直接封装成个warpper就行了
爱蹄子的羊头 2013-02-01
  • 打赏
  • 举报
回复
引用 3 楼 Behard 的回复:
两个问题: 1. 在 dll 和 exe 中都应该指定调入方式,如 WINAPI (也就是__stdcall) extern "C" __declspec(dllexport) IMpkManip* __stdcall createMpkManip(); 2. 一般不要跨开发工具导出类指针,而是导出标准函数,如 int, unsigned char 等 ……
DLL 是第三方的. 不开源..
爱蹄子的羊头 2013-02-01
  • 打赏
  • 举报
回复
引用 5 楼 dataxdata 的回复:
CB有时就出这样的问题,不行就再用一个DLL封装一下
这个方法可以. 不过已经是下下策了.. 有没有更好的解决办法啊?
dataxdata 2013-01-31
  • 打赏
  • 举报
回复
CB有时就出这样的问题,不行就再用一个DLL封装一下
Behard 2013-01-31
  • 打赏
  • 举报
回复
调用约定: __cdecl 缺省 是 Borland C++ 的缺省的 C 格式命名约定,它在标识符前加一下划线,以保留 它原来所有的全程标识符。参数按最右边参数优先的原则传递给栈,然后清栈。 extaern "C" bool __cdecl TestFunction(); 在 def 文件中显示为 TestFunction @1 注释: @1 表示函数的顺序数,将在“使用别名”时使用。 __pascal Pascal格式 这时函数名全部变成大写,第一个参数先压栈,然后清栈。 TESTFUNCTION @1 //def file __stdcall 标准调用 最后一个参数先压栈,然后清栈。 TestFunction @1 //def file __fastcall 把参数传递给寄存器 第一个参数先压栈,然后清栈。 @TestFunction @1 //def file
Behard 2013-01-31
  • 打赏
  • 举报
回复
两个问题: 1. 在 dll 和 exe 中都应该指定调入方式,如 WINAPI (也就是__stdcall) extern "C" __declspec(dllexport) IMpkManip* __stdcall createMpkManip(); 2. 一般不要跨开发工具导出类指针,而是导出标准函数,如 int, unsigned char 等
爱蹄子的羊头 2013-01-31
  • 打赏
  • 举报
回复



左边是 VC 的demo 右边是 C++Builder 的 demo

求大神帮忙看一下.
爱蹄子的羊头 2013-01-31
  • 打赏
  • 举报
回复
在 OllyDbg 里面下断点后发现 VC 调用的参数是正常的 C++Builder 调用的 ("c:\\1.txt") 变成了第二个参数 // 是调用约定的问题吗? 应该都是 cdecl才对啊?
自己下载正式版2.3,二进制下自己破解。参考偷梁换柱破解SkinMagic_百度文库中的文档,思想是PostMessageA替换MessageBoxA。下面是帖子的具体内容 不知道有多少像本人一样一直热爱着vc的人存在,应该很多吧.虽然CB也用的是c++的语法,但是由于是个人偏激吧,不太喜欢,所以就一直忍受着做界面的痛苦.用Vc写程序的都知道,MFC做界面是多么痛苦的事情,动不动就要继承,封装....十分的郁闷。以后前段时间让我遇到了SkinMagicToolkit,才知道,世界上既然还有那么可爱的软件存在(帮作者做一下广告先),简单的调用几句代码,就可以改变界面皮肤~换皮肤也很简单。真是个好东西~.好了,不说多废话了,开始。 我下载的是SkinMagicToolkit2.21.下载回来以后,发现按照例子调用以后,可以是可以改变皮肤,但是都会在程序界面显示前跳出一个对话框,显示内容是:ThisapplicationusestrialversionofSkinMagicToolkit.Youcanregisterathttp://www.appspeed.com 真难看,破解!把这个难看的对话框去掉。先检查壳。结果是没有~好~用W32dsm8.93中文版.先进行静态分析.SkinMagic里所有的函数其实就是在SkinMagicTrial.dll这里面了.用W32dsm8.93打开SkinMagicTrial.dll。然后"参考"->"串式参考".找到对话框信息.一直往下翻.看见这个信息"Thisapplicationusestrialversion",双击。这个时候,程序代码来到了:100061816878BC0510push1005BC78.字符信息就是在这里入栈的.往下看几行,把MessageBoxA的4个参数都入栈了以后,再下两行就是MessageBoxA函数的调用处了,在:10006192FF150c040510,这里就是调用MessageBoxA的地方.好的,马上用最简单的办法,把这里的入栈的4个参数都用nop给替换掉.我用的是Hiewv6.81。不一会,就把这4个push*****替换成了nop。马上运行已经写好的程序,因为程序是调用SkinMagicTrial.dll的,所以不用改任何程序的代码,就可以运行了。结果发现,跳出错误对话筐,说程序初始化错误,就退出了程序.....真郁闷....难道程序在其他的地方检查了Eax寄存器?Eax寄存器是用来保存每个函数调用完以后的返回值的.算了,我也懒得麻烦去做其他的事情了,要的就是爆破.仔细想一下,有什么函数也是调用4个参数的,而且要SkinMagicTrial.dll已经倒入的。有了! PostMessageA,马上看一下PostMessageA在SkinMagicTrial.dll中的地址."菜单"->"函数"->"输入",然后找到PostMessageA.双击,看见了PostMessageA的调用地址: 10023FF1FF15C4030510.好的,等一下就可以在:10006192FF150C040510,把FF150C040510替换成为FF15C4030510就可以了.因为PostMessageA也有返回值.呵呵。破解成功。这样,运行的时候再也不会跳出烦恼的对话框了.
一款用于共享软件加密的动态链接库文件,包含了获取硬盘物理序列号及BlowFish、MD5、SHA512、RIPEMD160、Secret16、MD5FileCheck、CRCFileCheck等多种强大加密算法,可以非常方便的用于软件的各类加密需求。支持VC/VB/BCB/Delphi等各类Windows平台下的开发工具,软件同时提供详细的函数定义说明、示例及各类开发工具使用的源代码。 软件功能: (1)可用于获取硬盘序列号(IDE/SCSI),支持Win9x/Me/NT/2000/XP。 (2)内置BlowFish、MD5、SHA512、RIPEMD160、Secret16、MD5FileCheck、 CRCFileCheck等多种强大加密算法来对软件进行加密保护。 (3)支持Window平台下的各类开发工具,如VC/VB/BCB/Delphi/PB/VFP等。 (4)可以非常方便的同时使用多种加密算法来对软件进行加密保护。 打包文件说明: Reg.dll-------------------加密算法动态链接库文件。 Reg.h---------------------在 VC(C/C++) 和 BCB 开发环境下的头文件。 Reg.lib-------------------在 VC(MFC) 开发环境下的 Library 文件。 Reg.bas-------------------在 VB 开发环境下的 Module 文件。 Readme.txt----------------纯文本格式说明文件。 Help.chm------------------函数接口详细定义说明文件。 MFC_TestEncryDll.zip------MFC调用Reg.dll进行加密示例。 VB6_TestEncryDll.zip------VB6调用Reg.dll进行加密示例。 CB5_TestEncryDll.zip------BCB5调用Reg.dll进行加密示例。 Delphi_TestEncryDll.zip---Delphi调用Reg.dll进行加密示例。 函数详细说明请参见Help.chm中具体函数说明部分及相关示例代码。

13,825

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧