OPENSSL_Uplink(0098E000,07): no OPENSSL_Applink 错误分析

分析1:
我新建了一个dll A.dll,而A.dll要调用openssl的dll, 然后新建一个win32应用程序B去调用A中的导出函数,此时必须include一次且仅一次 <install-root>/include/openssl/applink.c 到你的B工程里去,而不能include到A.dll工程里,或者把<install-root>/include/openssl/applink.c拷贝到B个工程里去,否则就会出现,运行时错误 OPENSSL_Uplink(0098E000,07): no OPENSSL_Applink

因为openssl源码Uplink.c中是这样子 : h=GetModuleHandle(NULL))   applink=(void**(*)())GetProcAddress(h,"OPENSSL_Applink");
可以看出 openssl 通过GetModuleHandle(NULL)取得的句柄h去调用Applink()函数(Applink函数就是applink.c中的一个导出函数), Applink()函数不属于openssl的dll内部函数的一部分(通过dll分析器看出这个函数不存在),但是因为GetModuleHandle(NULL)取得的句柄会始终指向应用程序的句柄(比如上面例子中的B工程)而非dll句柄, 所以必须把applink.c文件应用程序的一部分编译.

下面是我在openssl-user mail list中的提问,和有些人给我的答复:

From: yangniancai@hotmail.com
To: openssl-users@openssl.org
Subject: RE: OPENSSL_Uplink(0099E000,07): no OPENSSL_Applink
Date: Wed, 12 Nov 2008 01:51:11 +0000

hi Ger Hobbelt
 thank you soooooooo much .
your answer 2) solve my problem well. 
because there exists libeay32.dll ,ssleay32.dll ,my own dll and my application. my own dll call  libeay32.dll and ssleay32.dll. And my application call my own dll.
according to Ger Hobbelt's suggestion 2), firstly I used a tool to analyse the exports functions of  libeay32.dll ,ssleay32.dll and  my own dll.  I found that dll exports functions don't contain OPENSSL_Applink() function.  Also I look up the source code of Uplink.c which call OPENSSL_Applink() function.  Uplink.c use  <h=GetModuleHandle(NULL)> to get a handle h, and then use <applink=(void**(*)())GetProcAddress(h,"OPENSSL_Applink")> to got the address of OPENSSL_Applink() .  when I use libeay32.dll ,ssleay32.dll in my application , this handle h will point to the application but not my own dll.
So I should add applink.c to my application as a part of my application source code , never add it to my own dll source code.
 
Leo Yang

Best Regards
 
MSN: yangniancai@hotmail.com



> Date: Tue, 11 Nov 2008 17:35:03 +0100
> From: ger@hobbelt.com
> To: openssl-users@openssl.org
> Subject: Re: OPENSSL_Uplink(0099E000,07): no OPENSSL_Applink
> CC: i-zw@hotmail.com

> Hm, never used this OPENSSL_Uplink/Applink glue before... (I have my
> own OpenSSL MSVC2005 projects, which I always use inside my solutions)

> Anyway, a quick check leads me to two possible answers:

> 1) somewhere APPMACROS_ONLY was #define'd before your actual

> > extern "C"
> > {
> > #include <openssl/applink.c>
> > }

> code bit.

> A simple change should be able to verify if this is actually the matter:

> extern "C"
> {
> #undef APPMACROS_ONLY
> #include <openssl/applink.c>
> }

> as then the problem should be gone.

> However, there's a chance:

> 2) ... that you are compiling this code into a DLL of your own (given
> your description of the issue, my guess is this is what you are doing.
> Correct?).

> Given that the Uplink code looks at the *application module* for the
> Applink export, you may not find it when it is actually exported from
> a DLL instead of the EXE itself.

> NOTE: the above is 'guesswork': I haven't checked.


> To fix the above, moving the

> > extern "C"
> > {
> > #include <openssl/applink.c>
> > }

> code snippet to the main application source code should resolve the
> matter, preferrably by placing it in the same source file as your
> WinMain() / main() function.



> To help you see who exports what and depends on whom, you may search
> the Net for a free tool called 'Dependency Walker' (
> http://www.dependencywalker.com/ ) which is a very handy tool when you
> need to check what is going regarding DLL/EXE dependencies and
> function/data import/exports.






> On Tue, Nov 11, 2008 at 11:09 AM, 念材 杨 <yangniancai@hotmail.com> wrote:
> > hi all
> >
> > I meet a run time error "OPENSSL_Uplink(0099E000,07): no OPENSSL_Applink"
> > which feaze me several days.
> > this is my project description:
> > I had download openssl-0.9.8i. then build it and install it correctly
> > following the INSTALL.WIN32 instruction.
> > I use vs2005 to develop my project
> > and I had set vs2005 environment such as "MultiThread Debug DLL" etc.
> > Because it works well in my other projects.
> > this project is a bit different because the below function is called by a
> > dll project. but the function is the same in dll project and application
> > project.
> > [source code]
> > // "MyCryptlib.cpp"
> > #include "stdafx.h"
> > #include <openssl/ssl.h>
> > #include "MyCryptlib.h"
> > #include <iostream>
> > using namespace std;
> > extern "C"
> > {
> > #include <openssl/applink.c>
> > }
> > CONF *config=NULL;
> > BIO *bio_err=NULL;
> > // encrypt data
> > #define RSA_SIGN 1
> > #define RSA_VERIFY 2
> > #define RSA_ENCRYPT 3
> > #define RSA_DECRYPT 4
> > #define KEY_PRIVKEY 1
> > #define KEY_PUBKEY 2
> > #define KEY_CERT 3
> > //int EncryptData()
> > int EncryptData(unsigned char* indata, unsigned char* outdata, char*
> > pubkeyfile, int& len)
> > {
> >
> >
> > ENGINE *e = NULL;
> > BIO *in = NULL, *out = NULL;
> > char *infile = NULL, *outfile = NULL;
> > #ifndef OPENSSL_NO_ENGINE
> > char *engine = NULL;
> > #endif
> > char *keyfile = NULL;
> > char rsa_mode = RSA_VERIFY, key_type = KEY_PRIVKEY;
> > int keyform = FORMAT_PEM;
> > char need_priv = 0, badarg = 0, rev = 0;
> > char hexdump = 0, asn1parse = 0;
> > X509 *x;
> > EVP_PKEY *pkey = NULL;
> > RSA *rsa = NULL;
> > unsigned char *rsa_in = NULL, *rsa_out = NULL, pad;
> > char *passargin = NULL, *passin = NULL;
> > int rsa_inlen, rsa_outlen = 0;
> > int keysize;
> > int ret = 1;
> >
> > CRYPTO_malloc_init();
> > SSL_library_init();
> > if(!bio_err) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
> > if (!load_config(bio_err, NULL))
> > goto end;
> > ERR_load_crypto_strings();
> > OpenSSL_add_all_algorithms();
> > pad = RSA_PKCS1_PADDING;
> >
> >
> > rsa_mode = RSA_ENCRYPT;
> > key_type = KEY_PUBKEY;
> > keyfile = pubkeyfile;
> > //infile = "data.txt";
> > //outfile = "data.ssl";
> > //cerr <<"just for testing BIO_printf/n" << endl;
> >
> > if(need_priv && (key_type != KEY_PRIVKEY)) {
> > BIO_printf(bio_err, "A private key is needed for this operation/n");
> > goto end;
> > }
> > #ifndef OPENSSL_NO_ENGINE
> > e = setup_engine(bio_err, engine, 0);
> > #endif
> > if(!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
> > BIO_printf(bio_err, "Error getting password/n");
> > goto end;
> > }
> > /* FIXME: seed PRNG only if needed */
> > app_RAND_load_file(NULL, bio_err, 0);
> >
> > switch(key_type) {
> > case KEY_PRIVKEY:
> > pkey = load_key(bio_err, keyfile, keyform, 0,
> > passin, e, "Private Key");
> > break;
> > case KEY_PUBKEY:
> > pkey = load_pubkey(bio_err, keyfile, keyform, 0,
> > NULL, e, "Public Key");
> > break;
> > case KEY_CERT:
> > x = load_cert(bio_err, keyfile, keyform,
> > NULL, e, "Certificate");
> > if(x) {
> > pkey = X509_get_pubkey(x);
> > X509_free(x);
> > }
> > break;
> > }
> > if(!pkey) {
> > return 1;
> > }
> > rsa = EVP_PKEY_get1_RSA(pkey);
> > EVP_PKEY_free(pkey);
> > if(!rsa) {
> > BIO_printf(bio_err, "Error getting RSA key/n");
> > ERR_print_errors(bio_err);
> > goto end;
> > }
> >
> > if(infile) {
> > if(!(in = BIO_new_file(infile, "rb"))) {
> > BIO_printf(bio_err, "Error Reading Input File/n");
> > ERR_print_errors(bio_err);
> > goto end;
> > }
> > } else in = BIO_new_fp(stdin, BIO_NOCLOSE);
> > if(outfile) {
> > if(!(out = BIO_new_file(outfile, "wb"))) {
> > BIO_printf(bio_err, "Error Reading Output File/n");
> > ERR_print_errors(bio_err);
> > goto end;
> > }
> > } else {
> > out = BIO_new_fp(stdout, BIO_NOCLOSE);
> > #ifdef OPENSSL_SYS_VMS
> > {
> > BIO *tmpbio = BIO_new(BIO_f_linebuffer());
> > out = BIO_push(tmpbio, out);
> > }
> > #endif
> > }
> > keysize = RSA_size(rsa);
> > rsa_in = (unsigned char *)OPENSSL_malloc(keysize * 2);
> > rsa_out = (unsigned char *)OPENSSL_malloc(keysize);
> > /* Read the input data */
> > //rsa_inlen = BIO_read(in, rsa_in, keysize * 2);
> > rsa_inlen = strlen((char *)indata);
> > strcpy((char*)rsa_in, (char*)indata);
> > if(rsa_inlen <= 0) {
> > BIO_printf(bio_err, "Error reading input Data/n");
> > exit(1);
> > }
> >
> > if(rev) {
> > int i;
> > unsigned char ctmp;
> > for(i = 0; i < rsa_inlen/2; i++) {
> > ctmp = rsa_in[i];
> > rsa_in[i] = rsa_in[rsa_inlen - 1 - i];
> > rsa_in[rsa_inlen - 1 - i] = ctmp;
> > }
> > }
> > switch(rsa_mode) {
> > case RSA_VERIFY:
> > rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad);
> > break;
> > case RSA_SIGN:
> > rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad);
> > break;
> > case RSA_ENCRYPT:
> > rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad);
> > break;
> > case RSA_DECRYPT:
> > rsa_outlen = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad);
> > break;
> > }
> >
> > if(rsa_outlen <= 0) {
> > BIO_printf(bio_err, "RSA operation error/n");
> > ERR_print_errors(bio_err);
> > goto end;
> > }
> > memcpy(outdata, rsa_out, rsa_outlen);
> > outdata[rsa_outlen] = 0;
> > len = rsa_outlen;
> > //cout<<"%%%%%%%%%%len%%%%%%%%%"<<len<<endl;
> > ret = 0;
> > if(asn1parse) {
> > if(!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) {
> > ERR_print_errors(bio_err);
> > }
> > } else if(hexdump) BIO_dump(out, (char *)rsa_out, rsa_outlen);
> > else BIO_write(out, rsa_out, rsa_outlen);
> > end:
> > RSA_free(rsa);
> > BIO_free(in);
> > BIO_free_all(out);
> > if(rsa_in) OPENSSL_free(rsa_in);
> > if(rsa_out) OPENSSL_free(rsa_out);
> > if(passin) OPENSSL_free(passin);
> > return ret;
> > }
> >
> > this function use a pass in a buffer (indata) , and expect a buffer
> > (outdata) out. outdata contains encrypted data.
> >
> > please help me ! thank you for your kind in advance.
> >
> > by the way, I wirte above EncryptData function referring to rsa source code.
> >
> >
> >
> >
> >
> >
> >
> > ________________________________
> > Invite your mail contacts to join your friends list with Windows Live
> > Spaces. It's easy! Try it!



> -- 
> Met vriendelijke groeten / Best regards,

> Ger Hobbelt

> --------------------------------------------------
> web: http://www.hobbelt.com/
> http://www.hebbut.net/
> mail: ger@hobbelt.com
> mobile: +31-6-11 120 978

面向工程应用:市面上的一些密码学课程和密码学的书籍,很多都是从考证出发,讲解算法原理并不面向工程应用,而我们现在缺少的是工程应用相关的知识,本课程从工程应用出发,每种技术都主要讲解其在工程中的使用,并演示工程应用的代码。 从零实现部分算法: 课程中实现了base16编解码 ,XOR对称加解密算法,PKCS7 pading数据填充算法,通过对一些简单算法的实现,从而加深对密码学的理解。理论与实践结合: 课程如果只是讲代码,同学并不能理解接口背后的原理,在项目设计中就会留下隐患,出现错误也不容易排查出问题。如果只讲理论,比如对密码学的一些研究,对于大部分从事工程应用的同学并没有必要,而是理论与实践结合,一切为了工程实践。代码现场打出: 代码不放在ppt而是现场打出,更好的让学员理解代码编写的逻辑,老师现场敲出代码正是展示出了工程项目的思考,每个步骤为什么要这么做,考虑了哪些异常,易学不枯燥: 课程为了确保大部分人开发者都学得会,理解算法原理(才能真正理解算法特性),学会工程应用(接口调用,但不局限接口调用,理解接口背后的机制,并能解决工程中会出现的问题),阅读算法源码但不实现密码算法,,并能将密码学投入到实际工程中,如果是想学习具体的加密算法实现,请关注我后面的课程。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值