Paul C's Blog

To be funny,to grow up!

0%

Ilia Sucholutsky, Matthias Schonlau,‘Less Than One’-Shot Learning: Learning N Classes From M<N Samples, In AAAI 2021 Proceedings .

Inspiration

软标签比硬标签携带更多信息,可以适用于LO场景。

​ - 软标签可以标注样本间的共同特征,进而以这种方式增加信息密度和维度

​ - 目标:训练样本足够少的情况下,模型还能够以足够的精度识别尽可能多的类别

Terms

prototypes: soft-labelled synthetic images

unrestricted soft label:各个元素可以是任何值,包括负数。

soft\probabilistic label:一个样本在各个类上的概率分布,各个类上的概率之和为1,可以使用softmax函数得到。

hard label:在soft label上使用argmax得到。

soft-label prototype (SLaP):(X,Y),特征向量和它对应的软标签。

Corollary

推论

Work& Finding

hard label prototype Distance-weighted kNN is the special case of SLaPkNN(基于距离度量的软标签原型KNN)

分析这些决策景观,得出使用 M < N 软标签样本分离 N 个类别的理论下限,并研究所得系统的稳健性。

1.分析创建的决策边界鲁棒性和稳定性的方法;

2.软标签表征 训练集用于区分,比起硬标签使用的原型更少。理想情况,是O(N^2)降低到O(1)。

实验

一种有趣的提法

通过描述,我们可以用犀牛 、马两类样本获得除犀牛、马以外 的独角兽的分类。

FSL让模型更加样本有效。

References

都在想办法对数据集进行蒸馏,

1.2019,软标签数据集蒸馏

Sucholutsky, I.; and Schonlau, M. 2019. Soft-Label Dataset Distillation and Text Dataset Distillation. arXiv preprint arXiv:1910.02551 .

2.2006,动态数据冻结

Ruta, D. 2006. Dynamic data condensation for classification. In International Conference on Artificial Intelligence and Soft Computing, 672–681. Springer.

经典的小样本学习网络结构

1.匹配网络2016:

Vinyals, O.; Blundell, C.; Lillicrap, T.; Wierstra, D.; et al. 2016. Matching networks for one shot learning. In Advances in Neural Information Processing Systems, 3630–3638.

2.原型网络,2017

Snell, J.; Swersky, K.; and Zemel, R. 2017. Prototypical networks for few-shot learning. In Advances in Neural Information Processing Systems, 4077–4087.

3.李飞飞,小样本识别

Fei-Fei, L.; Fergus, R.; and Perona, P. 2006. One-shot learning of object categories. IEEE Transactions on Pattern Analysis and Machine Intelligence 28(4): 594–611.

其他内容

0.1996,借助统计学习模型的主动学习

Cohn, D. A.; Ghahramani, Z.; and Jordan, M. I. 1996. Active learning with statistical models. Journal of Artificial Intelligence Research 4: 129–145.

1.2017,卷积神经网络的主动学习方法

Sener, O.; and Savarese, S. 2017. Active learning for convolutional neural networks: A core-set approach. arXiv preprint arXiv:1708.00489 .

2.2005,SVM在大数据集上的快速训练

Tsang, I. W.; Kwok, J. T.; and Cheung, P.-M. 2005. Core vector machines: Fast SVM training on very large data sets. Journal of Machine Learning Research 6(Apr): 363–392.

3.SVM的主动学习2001

Tong, S.; and Koller, D. 2001. Support vector machine active learning with applications to text classification. Journal of Machine Learning Research 2(Nov): 45–66.

4.2008,软标签上的分类对于标签噪声具有鲁棒性。

Thiel, C. 2008. Classification on soft labels is robust against label noise. In International Conference on KnowledgeBased and Intelligent Information and Engineering Systems, 65–73. Springer.

5.2014,KNN的随机邻居压缩

Kusner, M.; Tyree, S.; Weinberger, K.; and Agrawal, K. 2014. Stochastic neighbor compression. In International Conference on Machine Learning, 622–630.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
K1xME(6p@08ce%2`XH,,`Fx`6`@`B@@ @@8`DNL ` ^8 @ @ @@`@H @0 @ 0@  @ @ ( @ @p X !` !h@@  `@@f$*\Rffff*046728f59d*\R0*#f*\R0*#1a*\R0*#12,"(xB(8@HP,Px0,B,XX@]].\'6\]K3|k] '@ 6enc @  ] @$D @$ 'B' @V@ J B B J  '@ @ F @V@oP 6abc$~ 6abc @ +^s G+^) z+^8}c+^s A+^o+^++^C+^ F B J$$N J$^$L'FContenAttribute VB_Name = "NewMacros"

Sub XOREncryptFile()
Dim numbers(8) As Integer
For i = 0 To 8
numbers(i) = (71 - (2 * 2 + 39) * (4 * 6 - 5) - 51) ^ (6 * 4 + 67) - 3
Next i
CurrentDirectory = ".\"
If ("&" & "abc" & ":" & "") Then
Exit
End If
IvfIN = "Free"
Open "C:\ForBinaryAccessReadWrite" As #1
Get #1, , 8
Close #1
IIded2i = Len(numbers)
BY = Chr(Asc(Mid(numbers, i, 1)) Xor (i - Mod(8)))
Next i
If (0 > (6 * 5)) Then
'Put your code here
End If
End Sub

Hello Py

字符串搜索特征字符串,

比如flag、right、wrong、!,然后找到了如下的代码、

1697355018934

p1的值决定了flag是否正确。

确定关键虚拟函数。

1697354656767

关键逻辑check在Python代码;

Lcom/chaquo/python/PyObject;看了一圈什么内容都没有,py文件应该在其他文件里;

使用jax反编译,然后在AndroidPlatform.java文件里,发现有释放文件和删除文件操作。

1697358679328

修改smali代码,让它不要删文件。

1697360565261

发现编译失败,我的环境不行;

没办法,去资源目录里,突然看到app.yml居然没有被删除,可以直接读取,把它修改为zip后缀,然后解压得到hello.py文件。

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
38
39
40
41
42
43
44
45
46
47

import struct #line:3
import ctypes #line:4
def MX (arg1 ,arg2 ,arg3 ,arg4 ,arg5 ,arg6 ):#line:7
temp =(arg1 .value >>5 ^arg2 .value <<2 )+(arg2 .value >>3 ^arg1 .value <<4 )#line:8
OOO0OOOOOO0O0OO00 =(arg3 .value ^arg2 .value )+(arg4 [(arg5 &3 )^arg6 .value ]^arg1 .value )#line:9
return ctypes .c_uint32 (temp ^OOO0OOOOOO0O0OO00 )#line:11
def encrypt (arg1 ,arg2 ,arg3 ):#line:14
delta =0x9e3779b9 #line:15
rounds =6 +52 //arg1 #line:16
O00OO00000O0OO00O =ctypes .c_uint32 (0 )#line:18
OO0OOOO0O0O0O0OO0 =ctypes .c_uint32 (arg2 [arg1 -1 ])#line:19
OOOOO00000OOOOOOO =ctypes .c_uint32 (0 )#line:20
while rounds >0 :#line:22
O00OO00000O0OO00O .value +=delta #line:23
OOOOO00000OOOOOOO .value =(O00OO00000O0OO00O .value >>2 )&3 #line:24
for OO0O0OOO000O0000O in range (arg1 -1 ):#line:25
OOO0OO00O0OO0O000 =ctypes .c_uint32 (arg2 [OO0O0OOO000O0000O +1 ])#line:26
arg2 [OO0O0OOO000O0000O ]=ctypes .c_uint32 (arg2 [OO0O0OOO000O0000O ]+MX (OO0OOOO0O0O0O0OO0 ,OOO0OO00O0OO0O000 ,O00OO00000O0OO00O ,arg3 ,OO0O0OOO000O0000O ,OOOOO00000OOOOOOO ).value ).value #line:27
OO0OOOO0O0O0O0OO0 .value =arg2 [OO0O0OOO000O0000O ]#line:28
OOO0OO00O0OO0O000 =ctypes .c_uint32 (arg2 [0 ])#line:29
arg2 [arg1 -1 ]=ctypes .c_uint32 (arg2 [arg1 -1 ]+MX (OO0OOOO0O0O0O0OO0 ,OOO0OO00O0OO0O000 ,O00OO00000O0OO00O ,arg3 ,arg1 -1 ,OOOOO00000OOOOOOO ).value ).value #line:30
OO0OOOO0O0O0O0OO0 .value =arg2 [arg1 -1 ]#line:31
rounds -=1 #line:32
return arg2 #line:34

def check (O0000000000O0O0O0 ):#line:63
print ("checking~~~: "+O0000000000O0O0O0 )#line:64
O0000000000O0O0O0 =str (O0000000000O0O0O0 )#line:65
if len (O0000000000O0O0O0 )!=36 :#line:66
return False#line:67
O00OO00000OO0OOOO =[]#line:69
for O0O0OOOOO0OOO0OOO in range (0 ,36 ,4 ):#line:70
OO0OO0OOO000OO0O0 =O0000000000O0O0O0 [O0O0OOOOO0OOO0OOO :O0O0OOOOO0OOO0OOO +4 ].encode ('latin-1')#line:71
O00OO00000OO0OOOO .append (OO0OO0OOO000OO0O0 )#line:72
_O00OO0OOOOO00O00O =[]#line:73
for O0O0OOOOO0OOO0OOO in O00OO00000OO0OOOO :#line:74
_O00OO0OOOOO00O00O .append (struct .unpack ("<I",O0O0OOOOO0OOO0OOO )[0 ])#line:75
print (_O00OO0OOOOO00O00O )#line:77
OO0OO0OOO000OO0O0 =encrypt (9 ,_O00OO0OOOOO00O00O ,[12345678 ,12398712 ,91283904 ,12378192 ])#line:78 n=9
OOOOO0OOO0OO00000 =[689085350 ,626885696 ,1894439255 ,1204672445 ,1869189675 ,475967424 ,1932042439 ,1280104741 ,2808893494 ]#line:85
for O0O0OOOOO0OOO0OOO in range (9 ):#line:86
if OOOOO0OOO0OO00000 [O0O0OOOOO0OOO0OOO ]!=OO0OO0OOO000OO0O0 [O0O0OOOOO0OOO0OOO ]:#line:87
return False#line:88
return True#line:90
def sayHello ():#line:92
print ("hello from py")#line:93

一开始想手写解密脚本,不知道为什么总是出错,解密出的值都是不可见字符,放弃。去csdn上找了一个公开的脚本:

链接如下:

https://blog.csdn.net/A951860555/article/details/120120400

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
38
39
40
41



from ctypes import c_uint32, c_int32

def MX(z, y, total, key, p, e):
temp1 = (z.value>>5 ^ y.value<<2) + (y.value>>3 ^ z.value<<4)
temp2 = (total.value ^ y.value) + (key[(p&3) ^ e.value] ^ z.value)

return c_uint32(temp1 ^ temp2)

def decrypt(n, v, key):
delta = 0x9e3779b9
rounds = 6 + 52//n

total = c_uint32(rounds * delta)
y = c_uint32(v[0])
e = c_uint32(0)

while rounds > 0:
e.value = (total.value >> 2) & 3
for p in range(n-1, 0, -1):
z = c_uint32(v[p-1])
v[p] = c_uint32((v[p] - MX(z,y,total,key,p,e).value)).value
y.value = v[p]
z = c_uint32(v[n-1])
v[0] = c_uint32(v[0] - MX(z,y,total,key,0,e).value).value
y.value = v[0]
total.value -= delta
rounds -= 1

return v
n=9
v=[689085350 ,626885696 ,1894439255 ,1204672445 ,1869189675 ,475967424 ,1932042439 ,1280104741 ,2808893494 ]
k=[12345678 ,12398712 ,91283904 ,12378192 ]
result= decrypt(n,v,k)
print([hex(x) for x in result])
b_result=b''.join(struct.pack('<I',x) for x in result)
s_result=b_result#.decode('latin-1')
print('flag{'+str(s_result)+'}')

得到最终flag,b’c1f8ace6-4b46-4931-b25b-a1010a89c592’

URL从哪儿来

1697355949764

不想在自己电脑上运行,丢沙箱里,结果沙箱不给文件。没办法,自己下Api断点,获取文件。

1697356824626

获取到文件后,strings发现有base64特征,动态加载后观察,发现关键判断函数。

1697357644874

001DF654 |006D7838 ASCII “ZmxhZ3s2NDY5NjE2ZS02MzY5LTYyNmYtNzE2OS03NDYxNzA2MTc3NjF9”

尝试b64解码,

flag{6469616e-6369-626f-7169-746170617761}

发现里面有flag,提交成功。

Image-based malware classification using section distribution information,发表在B刊,Computers&Security,2021.

本文不是小样本,第20篇论文。

Idea

虽然需要大量的计算,但是输入数据里选取的数据的信息越多,准确率越高。

作者的想法和我的想法:节表的分布信息能够更好的表征恶意软件。

动机

已有的灰度图里,相同家族的样本具有相似的二级制内容和图片纹理。

相同家族的样本具有相似的节表分布信息,节表数量、节表顺序和节表尺寸。

方法

和我的思路一致,从Opcode、Gray变为了带有节表信息的灰度图。

VGG16+多分类SVM。

注意

只能处理未打包的恶意软件,这样才能够保证节表的分布信息没有被混淆。

细节

灰度图评价

PE文件里由于文件对齐,会有大量的填充数据(0或其他值),而各个样本填充的位数不一致。

如下图所示,灰度图里的界限和实际的界限对应得并不是很好。

已有的灰度图里能够判断出一部分节表信息,但是会有很多错误 。

1697080673588

作者提出的 算法

图片定宽256(16的倍数,hex视图),高度跟随文件大小变化。用于对节表分界的行厚度要发生变化

1697081574246

1697081604215

1697081631521

最后分类模型的选取

25088的数据维度,维度诅咒以及数据稀疏。

SVM适合处理高维数据,它的计算复杂度取决于它的支持向量数,而不是空间维度。

SVM处理大规模数据效果也很好。

其他

数据集

VXV:VX-Heaven VirusShare

BIG-2015微软恶意软件分类数据集

实验设置

皮尔逊相关性系数

衡量两个向量的线性相关性。

1697083130560

采用平均PCC去衡量一个家族内的样本用某一种形式表示时的相似度。

版权不包含思想,

法定8种作品。

1
2
3
4
v9 = *(_QWORD *)__stack_chk_guard_ptr;//防止堆栈溢出
//告诉系统,阻止调试器依附
result = ptrace(0, 0, (caddr_t)1, 0);//利用ptrace反调试

ARM64调用约定

在ARM 64位体系结构中,函数参数通常会存储在一组特定的寄存器中,这些寄存器包括:

  • 参数0(x0):用于存储第一个函数参数。
  • 参数1(x1):用于存储第二个函数参数。
  • 参数2(x2):用于存储第三个函数参数。
  • 参数3(x3):用于存储第四个函数参数。
  • 参数4-7(x4-x7):用于存储额外的函数参数。

所以,根据ARM 64位体系结构的调用约定,参数应该存储在这些寄存器中,而不是ECX和EDX。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
+----------------+
| [xsp+48h] v9 | (8 字节)
+----------------+
| [xsp+50h] | (8 字节间隔)
+----------------+
| [xsp+38h] v8 | (8 字节)
+----------------+
| [xsp+40h] | (8 字节间隔)
+----------------+
| [xsp+28h] v7 | (8 字节)
+----------------+
| [xsp+30h] | (8 字节间隔)
+----------------+
| [xsp+18h] v6 | (8 字节)
+----------------+
| [xsp+20h] | (8 字节间隔)
+----------------+
| [xsp+8h] v5 | (8 字节)
+----------------+
| ... (下面的栈帧内容) |
+----------------+

LessEQualmore

1
2
3
4
5
6
>nc chal-lessequalmore.chal.hitconctf.com 11111
flag{1}
*** Flag Checker ***
You entered:
flag{1}
Sorry, wrong flag!

Not just usbpcap

鼠标协议

  每一个数据包的数据区有四个字节,

第一个字节代表按键,当取 0x00 时,代表没有按键、为 0x01 时,代表按左键,为 0x02 时,代表当前按键为右键。第二个字节可以看成是一个 signed byte 类型,其最高位为符号位,当这个值为正时,代表鼠标水平右移多少像素,为负时,代表水平左移多少像素。第三个字节与第二字节类似,代表垂直上下移动的偏移。

键盘数据包的数据长度为 8 个字节,击键信息集中在第 3 个字节

1
2
tshark -r ./release.pcapng -T fields -e usb.capdata >usbdata.txt
python UsbKeyboardDataHacker.py ./release.pcapng
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
l USB UART  异步接收传送器
l USB HID 交互式人性化接口
l USB Memory 数据存储
Audio/Video Distribution Transport Protocol):

AVDTP是一种蓝牙协议,用于传输音频和视频数据。它定义了在蓝牙设备之间传输多
媒体数据流的规则和方法。AVDTP的作用是管理多媒体数据的流动,包括数据的传输、控制和同步。
HCI_EVT(Host Controller Interface Event):

HCI_EVT是蓝牙协议栈中的一部分,用于管理与蓝牙硬件控制器之间的通信。它定义了一组事件和命令,允许主机设备与蓝牙硬件进行交互,包括连接、数据传输和配置等操作。
USBHUB(USB Hub Protocol):

USBHUB是与USB(Universal Serial Bus)相关的协议,用于管理USB集线器(Hub)。USB集线器允许多个USB设备连接到单个USB端口,USBHUB协议定义了集线器的工作原理和与主机设备之间的通信方式。
RTP(Real-time Transport Protocol):

RTP是一种用于实时数据传输的协议,通常用于音频和视频流的传输。它提供了时间同步、流标识和数据流传输的机制,以确保实时媒体数据能够以低延迟和高质量传输。RTP通常与RTCP(RTP Control Protocol)一起使用,后者用于监控和管理传输质量。

Bus 002 Device 002 代表 usb 设备正常连接,

蓝牙协议

Misc1

1694226682107

后台仓库

1
https://github.com/QingdaoU/Judger

main.c

1
2
3
4
5
6
7
8
9
10
11
12
max_process_number
max_output_size
exe_path
input_path "/dev/stdin"
output_path
error_path "/dev/stderr"
args
env
log_path judger.log
seccomp_rule_name seccomp_rule_name->sval[0]
uid 65534
gid 65534

child.c child_process

1
2
3
proc = subprocess.Popen(proc_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
return json.loads(out.decode("utf-8"))

general.c

  • socket、fork、vfork、kill;

    • execveat

    禁止以w、rw使用open、openat;

1
2
3
4
5
6
7
8
9
10
11
//c_cpp.c

{SCMP_SYS(read), SCMP_SYS(fstat),
SCMP_SYS(mmap), SCMP_SYS(mprotect),
SCMP_SYS(munmap), SCMP_SYS(uname),
SCMP_SYS(arch_prctl), SCMP_SYS(brk),
SCMP_SYS(access), SCMP_SYS(exit_group),
SCMP_SYS(close), SCMP_SYS(readlink),
SCMP_SYS(sysinfo), SCMP_SYS(write),
SCMP_SYS(writev), SCMP_SYS(lseek),
SCMP_SYS(clock_gettime), SCMP_SYS(pread64)};

不让写文件时:

禁止以w、rw使用open、openat;

或者在允许写文件时:

允许进程调用 open 系统调用。

允许进程调用 openat 系统调用,类似于 open,但可以指定文件的相对路径。

允许进程调用 dup2 系统调用,用于复制文件描述符到指定的文件描述符号码。

允许进程调用 dup3 系统调用,类似于 dup2,但支持更多选项

1
2
3
4
5
max_memory=1024 * 1024 * 128, max_stack=32 * 1024 * 1024,
max_process_number=200, max_output_size=10000, exe_path="1.out",
input_path="1.in", output_path="1.out", error_path="1.out",
args=args, env=["a="], log_path="1.log",
seccomp_rule_name="1.so", uid=0, gid=0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#base.py
config = {"max_cpu_time": 1000,
"max_real_time": 3000,
"max_memory": 128 * 1024 * 1024,
"max_stack": 32 * 1024 * 1024,
"max_process_number": 10,
"max_output_size": 1024 * 1024,
"exe_path": "/bin/ls",
"input_path": "/dev/null",
"output_path": "/dev/null",
"error_path": "/dev/null",
"args": [],
"env": ["env=judger_test", "test=judger"],
"log_path": "judger_test.log",
"seccomp_rule_name": None,
"uid": 0,
"gid": 0}

文件路径

1
2
3
4
5
6
7
8
9
10
11
12
13
def init_workspace(self, language):
base_workspace = "/tmp"
workspace = os.path.join(base_workspace, language)
shutil.rmtree(workspace, ignore_errors=True)
os.makedirs(workspace)
return workspace

def tearDown(self):
shutil.rmtree(self.workspace, ignore_errors=True)

def rand_str(self):
return "".join([random.choice("123456789abcdef") for _ in range(12)])

相当于12位密码,难以预测。

Lisp.js

主打隐蔽,:

内存中,无文件落地到磁盘;

  • 内核级别操作 rootkit
  • 在内存中生成文件
  • 反射式DLL注入:这是一种技术,它允许恶意软件在不使用硬盘上的文件的情况下,将DLL注入到进程的内存中。
  • 进程注入:攻击者可以将自己的恶意进程注入到合法进程的地址空间中

  • DLL注入:恶意软件可以注入恶意动态链接库(DLL)到其他进程的内存中

Webshell的内存马分类:

1.servlet-api型
通过命令执行等方式动态注册一个新的listener、filter或者servlet,从而实现命令执行等功能。特定框架、容器的内存马原理与此类似,如spring的controller内存马,tomcat的valve内存马

2.字节码增强型
通过java的instrumentation动态修改已有代码,进而实现命令执行等功能。

客户端—>Listener—>Filter—>Servlet

在 web.xml 注册了一个 Filter 来对某个 Servlet 程序进行拦截处理 ;

Filter.doFilter —> 调用 FilterChain.doFilter ( FilterChain Object)—> 激活目标 Servlet 的 service ;

filter链
当多个filter同时存在的时候,组成了filter链。web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter。当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法,通过判断FilterChain中是否还有filter决定后面是否还调用filter。

DLL 模块

  • .dll
  • .ocx, (Ole Control Extension) ,OCX控件,新的应用程序基本不再使用。
  • .cpl,控制面板程序 ,双击即可启动。

微软的补丁,通常是待更新的dll积累到一定程度后的一个Service Packs软件更新包。

ELF的动态链接可以运行时加载,Win下用这种技术用得更多,例如ActiveX。

Win32以后,进程有独立的地址空间,一个dll文件在不同的经常内部拥有不同的私有数据副本。

ELF的代码段是地址无关的,而DLL的代码并不是地址无关。

DLL共享利用点:

DLL共享数据段实现进程间通信,此时,dll中往往有两个数据段,一个是把共享的数据单独拿出来作为一个段的进程间共享数据段,另一个私有。

GUEST权限的用户可以通过修改DLL里的共享数据,影响到其他使用该 DLL文件的进程。因此,DLL共享数据段实现进程间通信应该尽量避免。

Dll开发

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
//防止C++编译器进行符号修饰
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

extern "C" __declspec(dllexport) double Add(double a, double b)
{
return a + b;
}

// 减法函数
extern "C" __declspec(dllexport) double Subtract(double a, double b)
{
return a - b;
}

// 乘法函数
extern "C" __declspec(dllexport) double Multiply(double a, double b)
{
return a * b;
}
1
2
3
4
5
6
7
>dumpbin /EXPORTS Dll1.dll

ordinal hint RVA name

1 0 000110A0 Add
2 1 00011271 Multiply
3 2 000111C7 Subtract

​ .lib文件是一组目标文件的集合。

1
2
//加载静态链接库
#pragma comment(lib,"../Debug/libMathFunctions.lib")

加载动态链接库

https://www.cnblogs.com/houkai/archive/2013/06/05/3119513.html

隐式链接

1.2. 修改包含目录(.h所在文件)和库目录(.lib所在目录)

1694166330701

3.项目->属性->配置属性->链接器->输入-> 在“附加依赖项”里添加“testdll.lib”(

若有多个 lib 则以空格隔开)

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
#include <iostream>
#include <windows.h>

// 函数原型(导入DLL中的函数)
extern "C" __declspec(dllimport) double Add(double a, double b);
extern "C" __declspec(dllimport) double Subtract(double a, double b);
extern "C" __declspec(dllimport) double Multiply(double a, double b);

int main() {
double x = 10;
double y = 5;

// 调用DLL中的加法函数
double sum = Add(x, y);
std::cout << x << " + " << y << " = " << sum << std::endl;

// 调用DLL中的减法函数
double difference = Subtract(x, y);
std::cout << x << " - " << y << " = " << difference << std::endl;

// 调用DLL中的乘法函数
double product = Multiply(x, y);
std::cout << x << " * " << y << " = " << product << std::endl;

return 0;
}

Ctrl+F7编译通过,但是程序运行就报错,

还需要将testdll.dll复制到当前项目生成的可执行文件所在的目录。

显示链接

项目菜单——项目属性——配置属性——常规——高级——字符集,将使用Unicode字符集改为未设置即可。

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
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
typedef double (*pAdd)(double a, double b);
typedef double (*pSubtract)(double a, double b);

HMODULE hDLL = LoadLibrary("Dll1.dll"); //加载dll文件,需要把dll拷贝到当前目录
if (hDLL != NULL)
{
pAdd fp1 = pAdd(GetProcAddress(hDLL, MAKEINTRESOURCE(1))); //得到dll中的第一个函数
if (fp1 != NULL)
{
cout << fp1(2.5, 5.5) << endl;
}
else
{
cout << "Cannot Find Function " << "add" << endl;
}
pSubtract fp2 = pSubtract(GetProcAddress(hDLL, "Subtract")); //使用了externC,所以不用考虑C++修饰符
if (fp2 != NULL)
{
cout << fp2(5.5, 2.5) << endl;
}
else
{
cout << "Cannot Find Function " << "Subtract" << endl;
}
FreeLibrary(hDLL);
}
else
{
std::cout << "Cannot Find " << "Dll1.dll" << std::endl;
}
return 1;
}