C/C++逆向:寻找mian函数(其他编译配置特征)

news2024/9/23 2:30:13

在上篇文章中写了在逆向中定位main函数几种方法,其中有一种方法是通过编译器特征定位 main 函数(使用IDA分析简单demo程序获取特征,根据得到的特征可以定位相同编译器编译程序的main函数)。在上一篇文章中我们提取了VS环境(VS2017)中MSVC编译器编译配置与目标平台架构分别为Debugx86生成的程序特征,从而正确定位到了main函数所在位置。本篇文章主要写一下根据编译器特征定位main函数的方法,提取VS环境(VS2017)生成的编译配置与目标平台架构分别为Debug+x64Release+x86Release+x64以及GCC编译器编译生成的程序特征,从而定位到main函数。

1.Debug-x64程序特征提取

先准备一个Debug-x64的Hello World程序(以下称Demo程序);且准备程序的步骤都一样,后续就不再赘述:

接着右击项目生成程序即可;

打开程序所在文件夹,找到程序即可:

exe程序放入IDA(x64-bit)中进行加载解析;pdb文件也最好一并载入,即弹出以下窗口时选择yes:

.pdb文件包含了与可执行文件关联的调试符号和源代码信息。这些信息包括函数名、变量名、源代码行号等。在调试时,.pdb文件使得调试器能够将二进制代码映射回源代码,从而允许开发者查看变量的名称和类型、设置断点、查看调用堆栈以及源代码的确切行号等。没有.pdb文件,调试器只能展示汇编代码和原始的内存地址,极大地增加了调试的难度。

接着在函数窗口定位Demo程序main函数所在位置:

定位到main函数:

接着进行交叉引用(ctrl + x),提取特征(过程在上一篇文章中已经有详细说明,这篇文章就不再做过多赘述),这边补充一下小细节;若是在交叉引用的过程中出现了两个目标,且目标中包含Runtime_Function;此时一律不选Runtime_Function:

以下是笔者获取的程序(Debug-x64)特征:

第一个jmp
​
第一个call
​
第二个call
​
第一个jnz
sub     rsp, 68h
mov     ecx, 1
call    j___scrt_initialize_crt
movzx eax, al
test eax, eax
jnz short loc_140011FEF
​
​
第一个jmp
mov     [rsp+68h+var_48], 0
call    j___scrt_acquire_startup_lock
mov     [rsp+68h+var_47], al
cmp     cs:__scrt_current_native_startup_state, 1
jnz     short loc_140012012
mov     ecx, 7
call    j___scrt_fastfail
jmp     short loc_14001206A
​
​
第一个jz
movzx   ecx, [rsp+68h+var_47]
call    j___scrt_release_startup_lock
call    j___scrt_get_dyn_tls_init_callback
mov     [rsp+68h+var_38], rax
mov     rax, [rsp+68h+var_38]
cmp     qword ptr [rax], 0
jz      short loc_1400120C6
​
第一个jz
call    j___scrt_get_dyn_tls_dtor_callback
mov     [rsp+68h+var_30], rax
mov     rax, [rsp+68h+var_30]
cmp     qword ptr [rax], 0
jz      short loc_1400120F9
​
第一个call
​
第4个call
​
jmp main(跳转表)

接着根据特征进行动态调试定位main函数:

将程序拖如x64dbg中进行调试;按下F9来到自身程序模块中:

接着根据特征成功定位到main函数:

因为具体方法在上一篇文章中已经介绍过了,所以这篇文章主要的侧重点还是来比较一下生成的Debug-x86/x64程序的特征:

①Debug-x64特征
第一个jmp
​
第一个call
​
第二个call
​
第一个jnz
sub     rsp, 68h
mov     ecx, 1
call    j___scrt_initialize_crt
movzx eax, al
test eax, eax
jnz short loc_140011FEF
​
​
第一个jmp
mov     [rsp+68h+var_48], 0
call    j___scrt_acquire_startup_lock
mov     [rsp+68h+var_47], al
cmp     cs:__scrt_current_native_startup_state, 1
jnz     short loc_140012012
mov     ecx, 7
call    j___scrt_fastfail
jmp     short loc_14001206A
​
​
第一个jz
movzx   ecx, [rsp+68h+var_47]
call    j___scrt_release_startup_lock
call    j___scrt_get_dyn_tls_init_callback
mov     [rsp+68h+var_38], rax
mov     rax, [rsp+68h+var_38]
cmp     qword ptr [rax], 0
jz      short loc_1400120C6
​
第一个jz
call    j___scrt_get_dyn_tls_dtor_callback
mov     [rsp+68h+var_30], rax
mov     rax, [rsp+68h+var_30]
cmp     qword ptr [rax], 0
jz      short loc_1400120F9
​
第一个call
​
第4个call
​
jmp main(跳转表)
②Debug-x86特征:
第一个jmp
​
第一个call
push
mov 
call
​
第二个call
​
第一个jnz
mov     large fs:0, eax
mov     [ebp+ms_exc.old_esp], esp
push    1
call    j____scrt_initialize_crt
add     esp, 4
movzx   eax, al
test    eax, eax
jnz     short loc_411D7B
​
第一个jmp
mov     [ebp+var_1A], al
cmp     dword_41A158, 1
jnz     short loc_411DA0
push    7
call    j____scrt_fastfail
jmp     short loc_411E01
​
第一个jz
movzx   ecx, [ebp+var_1A]
push    ecx
call    j____scrt_release_startup_lock
add     esp, 4
call    sub_411195
mov     [ebp+var_20], eax
mov     edx, [ebp+var_20]
cmp     dword ptr [edx], 0
jz      short loc_411E51
​
第一个jz
call    sub_41123A
mov     [ebp+var_24], eax
mov     edx, [ebp+var_24]
cmp     dword ptr [edx], 0
jz      short loc_411E82
​
第一个call
call    ?invoke_main@@YAHXZ ; invoke_main(void)   
mov     [ebp+Code], eax
call    j____scrt_is_managed_app
movzx   ecx, al
test    ecx, ecx
jnz     short loc_411E9F
mov     edx, [ebp+Code]
​
第4个call
第一个jmp

前三个特征:Debug-x64与Debug-x86特征一致;

①Debug-x64特征
第一个jmp
​
第一个call
​
第二个call
②Debug-x86特征:
第一个jmp
​
第一个call
push
mov 
call
​
第二个call

第四个特征:主要的区别在于MSVC运行时初始化函数(j___scrt_initialize_crt)调用时所作的处理方式不同,以下是两者的具体区别分析:

①Debug-x64特征
第一个jnz
sub     rsp, 68h
mov     ecx, 1
call    j___scrt_initialize_crt
---------------------------------------
movzx eax, al
test eax, eax
jnz short loc_140011FEF
  1. 针对 x64架构(64位),使用了 rsp 这个x64 特有的寄存器。

  2. 使用寄存器传递函数参数(mov ecx, 1),不涉及栈操作来传递参数。该片段在调用函数前并没有通过 push 将参数压入栈,而是直接将参数放入寄存器 ecx,这是典型的 x64使用的fastcall调用约定。

在 x64 架构(64位)中,Windows 平台的调用约定通常使用 RCX, RDX, R8, R9 寄存器来传递前四个整数或指针类型的参数,返回值使用 RAX 寄存器。
②Debug-x86特征:
第一个jnz
mov     large fs:0, eax
mov     [ebp+ms_exc.old_esp], esp
push    1
call    j____scrt_initialize_crt
add     esp, 4
---------------------------------------
movzx   eax, al
test    eax, eax
jnz     short loc_411D7B

1.针对 x86架构(32位),使用了 espebpfs 等 x86 特有的寄存器和调用约定。

2.通过 push 指令将参数压入栈(push 1);参数通过 push 指令压栈,这是 x86 调用约定(如 stdcall、cdecl 等)的常见特征。

3.该片段代码 使用了add esp, 4代码进行栈清理操作,这说明该x86程序使用的是 cdecl 调用约定。

除了以上区别,其余的特征一致。接着来对比一下第五个特征:

①Debug-x64特征
mov     [rsp+68h+var_48], 0
call    j___scrt_acquire_startup_lock
-------------对比下面特征--------------------------------------
mov     [rsp+68h+var_47], al
cmp     cs:__scrt_current_native_startup_state, 1
jnz     short loc_140012012
-----------------------------------------
mov     ecx, 7
call    j___scrt_fastfail
jmp     short loc_14001206A
②Debug-x86特征:
mov     [ebp+var_1A], al
cmp     dword_41A158, 1
jnz     short loc_411DA0
-----------------------------------------
push    7
call    j____scrt_fastfail
jmp     short loc_411E01

通关观察可以看出,第五个特征中也是由于x86与x64程序所用的调用约定不同从而使得两个特征又些许差异,除了在使用call调用函数部分会存在区别以外,其他的特征基本是一致的。其余特征的区别也是一洋,这边就不做过多赘述了。

2.Release-x86程序特征提取

准备一个Release-x86程序:

将程序拖入IDA(32bit)进行解析;

再解析完成后,一样在函数窗口中搜索main函数:

在这里我们可以发现 IDA函数窗口中Release 模式下的程序显示的函数数量明显少于 Debug 模式下的程序;这种现象的主要原因在于编译器在 Release模式下会进行各种优化,导致一些函数被内联、删除或合并。以下是部分导致这种现象的具体原因:

①编译器优化
1>函数内联
编译器会将一些小的、频繁调用的函数直接替换为它们的代码实现,避免了函数调用的开销。这种优化会导致这些小函数在最终的可执行文件中不再作为单独的函数存在,而是被“内联”到调用它们的地方,结果是 IDA 在分析 Release 版本时,无法识别出这些函数,导致函数窗口中显示的函数数量减少。
2>死代码消除
编译器会删除在程序执行过程中永远不会被调用的代码和函数,减少可执行文件的大小,在 Debug 模式下,编译器不会执行这种优化,因此即使是未使用的函数也会出现在最终的可执行文件中。
3>代码折叠和合并:
对功能相似或相同的代码段进行折叠或合并,以减少代码的冗余度。这样会导致 IDA 将多个函数识别为一个函数或者直接将多个函数的代码合并成一个函数。
②去除调试信息
Release 模式下通常会去除调试信息,如符号信息(函数名、变量名等)和调试符号(如 PDB 文件),以保护程序的源代码结构和内部逻辑,并且减少可执行文件的大小。

接着回到正题,在定位到main函数后,接着就可以对Release-x86程序进行特征提取,这边步骤就省略了,最后得到的特征为:

第一个call
​
第二个call
​
第一个jmp
mov     [ebp+ms_exc.registration.TryLevel], 0
call    ___scrt_acquire_startup_lock
mov     [ebp+is_nested], al
cmp     ___scrt_current_native_startup_state, 1
jnz     short loc_4011D0
push    7               ; code
call    ___scrt_fastfail
jmp     short loc_401231
​
第一个jz
movzx   ecx, [ebp+is_nested]
push    ecx             ; is_nested
call    ___scrt_release_startup_lock
add     esp, 4
call    ___scrt_get_dyn_tls_init_callback
mov     [ebp+tls_init_callback], eax
mov     edx, [ebp+tls_init_callback]
cmp     dword ptr [edx], 0
jz      short loc_401281
​
第一个jz
call    ___scrt_get_dyn_tls_dtor_callback
mov     [ebp+tls_dtor_callback], eax
mov     edx, [ebp+tls_dtor_callback]
cmp     dword ptr [edx], 0
jz      short loc_4012B2
​
第一个call
​
第4个call

在这边可以看到Release程序的特征层数比较Debug程序的特征层数要来的少;最后根据特征定位到main函数:

3.Release-x64程序特征提取

生成Release-x64程序;

打开所在文件夹,并将其载入IDA(64-bit)中进行解析:

在IDA中一样先在函数窗口中定位main函数:

接着进行交叉引用,提取特征,步骤省略,最后得到的特征为:

第一个call
​
第二个call
​
第一个jmp
call    __scrt_acquire_startup_lock
mov     [rsp+68h+var_47], al
cmp     cs:__scrt_current_native_startup_state, 1
jnz     short loc_140001222
mov     ecx, 7          ; code
call    __scrt_fastfail
jmp     short loc_14000127A
​
第一个jz
movzx   ecx, [rsp+68h+var_47]
call    __scrt_release_startup_lock
call    __scrt_get_dyn_tls_init_callback
mov     [rsp+68h+target], rax
mov     rax, [rsp+68h+target]
cmp     qword ptr [rax], 0
jz      short loc_1400012D6
​
第一个jz
call    __scrt_get_dyn_tls_dtor_callback
mov     [rsp+68h+var_30], rax
mov     rax, [rsp+68h+var_30]
cmp     qword ptr [rax], 0
jz      short loc_140001309
​
第一个call
​
第四个call

接着根据特征成功定位main函数:

4.gcc程序特征定位main函数

gcc编译的Demo程序准备,在此之前系统中需要存在gcc环境;若没有的gcc环境的兄弟文章末尾领取。我这边也只记录64位的gcc特征定位main函数的过程。

1.准备一个C文件

接着在命令行中运行以下命令,生成exe程序:

gcc Hello.c -o Hello.exe

此时就可以开始进行特征提取了,将程序拖入IDA(64-bit)进行加载解析;

特征如下:

第二个call
​
第一个jnz
push    r13
push    r12
push    rbp
push    rdi
push    rsi
push    rbx
sub     rsp, 98h
xor     eax, eax
mov     ecx, 0Dh
lea     rdx, [rsp+0C8h+StartupInfo]
mov     rdi, rdx
rep stosq
mov     rdi, cs:_refptr_mingw_app_type
mov     r9d, [rdi]
test    r9d, r9d
jnz     loc_401470
​
​
第二个jmp
xor     eax, eax
xchg    rax, [rbx]
jmp     loc_40122C
mov     rcx, rdx        ; lpStartupInfo
call    cs:__imp_GetStartupInfoA
jmp     loc_4011B4
​
第一个jmp
mov     rax, gs:30h
mov     rbx, cs:_refptr___native_startup_lock
xor     ebp, ebp
mov     rsi, [rax+8]
mov     r12, cs:__imp_Sleep
jmp     short loc_4011E4
​
第一个jnz
mov     rax, rbp
lock cmpxchg [rbx], rsi
test    rax, rax
jnz     short loc_4011D3
​
第一个jz
xor     ebp, ebp
mov     rsi, [rax+8]
mov     r12, cs:__imp_Sleep
jmp     short loc_4011E4
cmp     rsi, rax
jz      loc_401410
​
第一个jnz
mov     rsi, cs:_refptr___native_startup_state
mov     ebp, 1
mov     eax, [rsi]
cmp     eax, 1
jnz     loc_401205
​
第2个jz
xor     ebp, ebp
mov     eax, [rsi]
cmp     eax, 1
jz      loc_401427
mov     eax, [rsi]
test    eax, eax
jz      loc_401480
​
第一个jmp
mov     rdx, cs:_refptr___xi_z
mov     dword ptr [rsi], 1
mov     rcx, cs:_refptr___xi_a
call    _initterm
jmp     loc_401219
​
第一个jz
mov     eax, [rsi]
test    eax, eax
jz      loc_401480
mov     cs:has_cctor, 
mov     eax, [rsi]
cmp     eax, 1
jz      loc_40143C
​
第一个jnz
mov     rdx, cs:_refptr___xc_z
mov     rcx, cs:_refptr___xc_a
call    _initterm
test    ebp, ebp
mov     dword ptr [rsi], 2
jnz     loc_40122C
​
第一个jz
mov     rax, cs:_refptr___dyn_tls_init_callback
mov     rax, [rax]
test    rax, rax
jz      short loc_401247
xor     r8d, r8d
mov     edx, 2
​
第一个jmp
call    __p__acmdln
xor     ecx, ecx
mov     rax, [rax]
test    rax, rax
jnz     short loc_4012B2
jmp     short loc_4012F7
​
第一个jz
mov     r8d, [rdi]
test    r8d, r8d
jz      short loc_401315
test    byte ptr [rsp+0C8h+StartupInfo.dwFlags], 1
mov     eax, 0Ah
jnz     loc_401400
​
​
第一个jle
mov     rcx, r12        ; Size
call    malloc
test    ebx, ebx
mov     rdi, cs:argv
mov     rbp, rax
jle     short loc_401387
​
第二个call:
mov     qword ptr [rax], 0
mov     cs:argv, rbp
call    __main
mov     rax, cs:_refptr___imp___initenv
mov     rdx, cs:envp
mov     ecx, cs:argc    ; argc
mov     rax, [rax]
mov     [rax], rdx
mov     r8, cs:envp     ; envp
mov     rdx, cs:argv    ; argv
call    main
mov     ecx, cs:managedapp
mov     cs:mainret, eax
test    ecx, ecx
jz      loc_40149E

gcc程序的特征定位比较诡异,所以这边简单做一个记录:

①首先按F9进入自身程序模块中

进入以后查看反汇编代码后发现并未存在特征:

此时先按F8进行程序运行,但是F8按着按着发现又回到了ntdll.dll模块当中,所以还需要按下F9;

回到自己领空后接着按F8运行代码,结果运行没一会儿又回到了ntdll.dll模块,继续按F9。

回到自己程序模块中后接着F8运行,若是又到ntdll.dll模块就再按F9以此类推,直到出现以下特征:

两个call,依照上述IDA中提取的特征,我们需要进入第二个call;接着就正常根据特征进行main函数的定位即可。

注:由于gcc编译程序最后一个特征比较明显,所以可以选择一直点击F8,直到最后一个特征出现后,即可根据最后一个特征成功定位到main函数。

第二个call:
mov     qword ptr [rax], 0
mov     cs:argv, rbp
call    __main
mov     rax, cs:_refptr___imp___initenv
mov     rdx, cs:envp
mov     ecx, cs:argc    ; argc
mov     rax, [rax]
mov     [rax], rdx
mov     r8, cs:envp     ; envp
mov     rdx, cs:argv    ; argv
call    main
mov     ecx, cs:managedapp
mov     cs:mainret, eax
test    ecx, ecx
jz      loc_40149E
GCC环境:关注VX_GZ号[风铃Sec]后台回复[mingw64]获取MinGW,后添加环境变量即可使用。如若不会,GZH后台回复。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2095979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软件测试专栏】软件测试 — 概念篇

博客主页:Duck Bro 博客主页系列专栏:软件测试专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ 软件测试 — 概念篇 关键词:软件需求、用户需求、开发…

从混乱到秩序:产品经理在需求变更中的关键角色

在软件开发过程中,需求是驱动整个项目的核心。需求的来源多种多样,包括客户、市场、领导等,产品经理的职责是将这些需求收集、整理并转化为可行的开发计划。本文将探讨需求的来源、产品经理的角色、软件开发中的挑战以及应对变化的策略。 需求…

Java小白一文讲清Java中集合相关的知识点(一)

集合 诞生缘由 数组 长度开始时必须指定,而且一旦指定,不能更改保存的必须为同一类型元素使用数组进行增/删元素所需要编写的代码–比较麻烦 Person[] pers new Person[1]; pers[0] new Person(); //此时增加新的Person对象呢? Person[…

【学习笔记】卫星通信NTN 3GPP标准化进展分析(一)-基本信息

一、引言: 本文来自3GPP Joern Krause, 3GPP MCC (May 14,2024) Non-Terrestrial Networks (NTN) (3gpp.org) 本文总结了NTN标准化进程以及后续的研究计划,是学习NTN协议的入门。 【学习笔记】卫星通信NTN 3GPP标准化进展分析(一&#xf…

前端开发第二节课

HTML常用的标签 文本格式化标签 在网页中&#xff0c;有时需要为文字设置粗体、斜体或下划线等效果&#xff0c;这时就需要用到HTML中的文本格式化标签使文字以特殊的方式显示。 标签语义&#xff1a;突出重要性&#xff0c;比普通文字更重要。 加粗 <strong></st…

Spring框架;Spring中IOC简介及搭建;Spring中AOP简介;

一&#xff0c;Spring介绍 Spring 的全称&#xff1a; Spring Framework Spring是一个优秀的开源的轻量级的企业应用开发框架&#xff0c;是为了解决企业应用程序开发复杂性而创建的。它大大简化了java企业级开发的复杂性&#xff0c;提供了强大&#xff0c;稳定的功能&#xf…

XR-Frame 实现 始终朝向屏幕(相机)的面片与模型

wxml&#xff0c;xr-frame中plane平面默认是趴在场景中的&#xff0c;需要先绕x轴渲染90度&#xff0c; // 面片 <xr-node id"l" position"-3.0 0 0.0"><xr-mesh rotation"90 0 0" geometry"plane" uniforms"u_base…

浅析synchronized锁升级的原理与实现 2

本文内容是继我的上篇博客 浅析synchronized锁升级的原理与实现 1-CSDN博客 目录 各状态锁的升级场景 无锁 --> 轻量级锁 偏向锁 --> 轻量级锁 偏向锁 --> 重量级锁 轻量级锁 --> 重量级锁 总结 各状态锁的升级场景 下面我们结合代码看下各状态锁的升级场景。…

VL53L1CB TOF开发(2)----多区域扫描模式

VL53L1CB TOF开发.2--多区域扫描模式 概述视频教学样品申请源码下载硬件准备主要特点生成STM32CUBEMX串口配置IIC配置XSHUTGPIO1X-CUBE-TOF1堆栈设置函数说明初始化设置预设模式 (Preset mode)VL53L1_SetPresetModeVL53L1_SetDistanceMode时间预算单个ROI&#xff08;Single R…

从 Oracle 到 TiDB 丨数据库资源评估指南

原文来源&#xff1a; https://tidb.net/blog/5058e24f 本文作者&#xff1a;柳冬冬 导读 在当今技术飞速发展的时代&#xff0c;传统单机数据库正面临着前所未有的挑战。随着人工智能、云计算和大数据的崛起&#xff0c;企业对数据库的性能、可靠性和扩展性的需求日益增…

wordcloud兼figma的词云图片python生成

文章目录 一.Figma1.简介2.特点 二.代码构成1.详细代码2.word.py代码详解3.成果图 一.Figma 1.简介 Figma是一款全平台可使用的使用软件&#xff0c;和Sketch功能差不多&#xff1b;但是他可以在Mac&#xff0c;Windows PC&#xff0c;Linux计算机甚至Chromebook&#xff0c;…

中国各地级市-产业增加值、产业升级、产业结构高级化(2000-2021年)

产业增加值、产业升级和产业结构高级化是衡量地区经济发展水平的重要指标&#xff1a; 产业增加值&#xff1a;指在一定时期内&#xff0c;单位产值的增长部分&#xff0c;体现了产值、产量和增加值的综合增长能力。 产业升级&#xff1a;指通过技术进步和效率提升&#xff0c…

5.sklearn-朴素贝叶斯算法、决策树、随机森林

文章目录 环境配置&#xff08;必看&#xff09;头文件引用1.朴素贝叶斯算法代码运行结果优缺点 2.决策树代码运行结果决策树可视化图片优缺点 3.随机森林代码RandomForestClassifier()运行结果总结 环境配置&#xff08;必看&#xff09; Anaconda-创建虚拟环境的手把手教程相…

产品售后|基于SprinBoot+vue的产品售后管理​​​​​​​系统(源码+数据库+文档)

产品售后管理系统 目录 基于SprinBootvue的产品售后管理系统 一、前言 二、系统设计 三、系统功能设计 管理员模块实现 客户模块实现 受理人员模块实现 工程师模块实现 厂商模块实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、…

STM32外部中断(总结了易出现的BUG)

本文主要讲述了&#xff0c;本人在使用STM32F103C8T6做项目时&#xff0c;使用到按键触发外部中断时&#xff0c;发现无法触发外部中断。通过查看寄存器找出问题的过程&#xff0c;并总结了出现该问题的原因。 出现的问题 在使用STM32F103C8T6做一个矩阵键盘任务时&#xff0…

【学习笔记】卫星通信NTN 3GPP标准化进展分析(五)- 3GPP Release19 研究计划

一、引言&#xff1a; 本文来自3GPP Joern Krause, 3GPP MCC (May 14,2024) Non-Terrestrial Networks (NTN) (3gpp.org) 本文总结了NTN标准化进程以及后续的研究计划&#xff0c;是学习NTN协议的入门。 【学习笔记】卫星通信NTN 3GPP标准化进展分析&#xff08;一&#xff…

R语言报错 | object ‘integral‘ not found whilst loading name

1、报错背景 Registered S3 method overwritten by htmlwidgets:method from print.htmlwidget tools:rstudio Error: package or namespace load failed for ‘Seurat’:object integral not found whilst loading namespace spatstat.core 当我想library&…

RabbitMQ~架构、能力、AMQP、工作模式、高可用、死信队列了、事务机制了解

RabbitMQ RabbitMQ是使用Erlang编写的一个开源的消息中间件。它实现了AMQP(高级消息队列协议)&#xff0c;并支持其他消息传递协议&#xff1a;例如STOMP(简单文本定向消息协议)和MQTT(物联网协议)。 支持多种客户端如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、…

4-7 使用bios 中断 读取磁盘

1 首先是逻辑。 首先来看一下 他的编译代码的逻辑。 可以看到我 生成的 实际上是 Boot.bin , 这个文件可不止一个扇区&#xff0c; 然后将这个文件写入到了&#xff0c; disk1.img 这里加载了 disk1.img , disk2.img 我不太理解。 但是可以跑通&#xff0c; 暂时先不管了。…

How can I change from OpenAI to ChatOpenAI in langchain and Flask?

题意&#xff1a;“在 LangChain 和 Flask 中&#xff0c;如何将 OpenAI 更改为 ChatOpenAI&#xff1f;” 问题背景&#xff1a; This is an implementation based on langchain and flask and refers to an implementation to be able to stream responses from the OpenAI …