前言

许久未更新,实在没想到这一拖就是几个月,小半年也过去了。这段时间,没能坚持写一下内容出来,也是没办法。工作了,就没有了上学时的清闲,但是这都是主观的。客观上还是有时间的,只不过是自己懒了,嘿嘿,不辩解了,回到正文吧,看看有没有小伙伴遇到这个问题。

问题描述

问题来源是现在空闲着写来玩的一个项目,主要是做U盘文件加密解密的一个小软件。这个时候,就需要加密算法了,我这么懒不可能手撸加密算法的,而且要是在加密的过程中,可以采用多种加密算法的话,就更好了。有OPENSSL和Cryptopp给我选,然后快乐的选择了Cryptopp,以为OPENSSL在大一我编译它的时候,给我留下了不少阴影,哈哈哈,当年可真菜,虽然现在也一样。

看一下导致问题的代码,摘抄一部分如下

1
2
3
4
5
6
 typedef EAX_Final<AES, true> aes_encryption;
typedef EAX_Final<AES, false> aes_decryption;
aes_encryption* encoder_;
aes_decryption* decoder_;
encoder_ = new aes_encryption();
encoder_->SetKeyWithIV(aes_key_, aes_key_.size(), iv_);

然后,编译的时候,快乐的报错就来了

1
2
3
4
5
6
1>symmetryEncrypt.obj : error LNK2001: 无法解析的外部符号 "protected: virtual void __cdecl CryptoPP::EAX_Base::SetKeyWithoutResync(unsigned char const *,unsigned __int64,class CryptoPP::NameValuePairs const &)" (?SetKeyWithoutResync@EAX_Base@CryptoPP@@MEAAXPEBE_KAEBVNameValuePairs@2@@Z)
1>symmetryEncrypt.obj : error LNK2001: 无法解析的外部符号 "protected: virtual void __cdecl CryptoPP::EAX_Base::Resync(unsigned char const *,unsigned __int64)" (?Resync@EAX_Base@CryptoPP@@MEAAXPEBE_K@Z)
1>symmetryEncrypt.obj : error LNK2001: 无法解析的外部符号 "protected: virtual unsigned __int64 __cdecl CryptoPP::EAX_Base::AuthenticateBlocks(unsigned char const *,unsigned __int64)" (?AuthenticateBlocks@EAX_Base@CryptoPP@@MEAA_KPEBE_K@Z)
1>symmetryEncrypt.obj : error LNK2001: 无法解析的外部符号 "protected: virtual void __cdecl CryptoPP::EAX_Base::AuthenticateLastHeaderBlock(void)" (?AuthenticateLastHeaderBlock@EAX_Base@CryptoPP@@MEAAXXZ)
1>symmetryEncrypt.obj : error LNK2001: 无法解析的外部符号 "protected: virtual void __cdecl CryptoPP::EAX_Base::AuthenticateLastFooterBlock(unsigned char *,unsigned __int64)" (?AuthenticateLastFooterBlock@EAX_Base@CryptoPP@@MEAAXPEAE_K@Z)
1>E:\UdiskEncryptTools.exe : fatal error LNK1120: 5 个无法解析的外部命令

20210120205550

分析问题

在这里可以清楚的看到它提示,缺少EAX_Base类下面的SetKeyWithoutResync、AuthenticateBlocks、Resync…这些函数。

跟进一下 EAX_Final 这个类,可以看到他是继承自 EAX_Base,而 EAX_Base 又继承自 AuthenticatedSymmetricCipherBase, 然后缺失的函数都在这里类里面。

部分代码摘抄如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class  CRYPTOPP_NO_VTABLE EAX_Base : public AuthenticatedSymmetricCipherBase
{
public:
// AuthenticatedSymmetricCipher
std::string AlgorithmName() const
...

template <class T_BlockCipher, bool T_IsEncryption>
class EAX_Final : public EAX_Base
{
public:
static std::string StaticAlgorithmName()
...

protected:
void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs &params);
void Resync(const byte *iv, size_t len);
size_t AuthenticateBlocks(const byte *data, size_t len);
void AuthenticateLastHeaderBlock();

好的,有定义和声明的话,肯定是没问题的。再编译一次这个cryptopp.dll看看,然后再编译咱们的项目。依旧是提示缺失这几个东西。我。。。。

不急,一步一步来,看看dll里面有没有这个EAX的东西,用DLL Export Viewer 打开 cryptopp.dll看看
太多了不想翻,直接搜 EAX

20210120211829

还真没有 -_-

那就说明了,编译dll的时候,就没有导出这个函数,那肯定找不到符号嗦。那我们只要将它声明导出函数就可啦。

解决之路

来打开cryptopp的项目,找到编译dll的项目

20210120212135

然后会发现找不到eax.h 和 eax.cpp

所以,手动添加进来,添加现有项即可

20210120212307

添加好之后,兴冲冲的编译dll,然后去编我的exe,然后还是没找到

所以还是有问题的,回去看eax的源码,比对一下其它有导出函数的类的区别

20210120212555

答案是一目了然的,它缺了一个宏来修饰,以下是这个宏的声明,是用来声明导出的

1
#  define CRYPTOPP_DLL __declspec(dllexport)

那解决方案也呼之欲出了,将这个宏加上就可

1
2
3
4
5
6
7
// eax.h
class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE EAX_Base : public AuthenticatedSymmetricCipherBase
{
public:
// AuthenticatedSymmetricCipher
std::string AlgorithmName() const
...

编译

编译一手

8核16线程的U跑起编译来简直不要太舒服
20210120213126

用工具看看是否有导出函数了,可以看到找到了,稳了

20210120213355

编译项目EXE去看看,也正常起来了

20210120213602

嗯,差不多了,问题解决了,文字也到这里了,要是能帮到遇到同样问题的同学就最好了,没的话,我下次扑街了也好看博客来找到解决方案