Android漏洞之战——整体加壳原理和脱壳技巧详解
一、前言
为了帮助更加方便的进行漏洞挖掘工作,前面我们通过了几篇文章详解的给大家介绍了动态调试技术、过反调试技术、Hook技术、过反Hook技术、抓包技术等,掌握了这些可以很方便的开展App漏洞挖掘工作,而最后我们还需要掌握一定的脱壳技巧,进行进一步助力我们漏洞挖掘的效率,本文主要介绍Android App加壳中的整体dex加壳,帮助大家掌握加壳的原理和脱壳的各种技能。
本文第二节主要讲述Android启动流程和加壳原理
本文第三节主要介绍整体加壳的实现
本文第四节主要讲当下脱壳点的概念
本文第五节讲述现有的脱壳技巧
二、相关介绍
1.Android App启动流程
(1)Android系统启动流程
我们要彻底的了解App加壳原理,首先我们从了解App的启动流程出发,先于App启动之前,Android系统是启动最早,下面我们来详细查看一下Android系统的启动过程:

我在Xposed源码定制一文中详细的讲解了Android的启动流程,简单来说就是:

| 1 |
|
我们就了解了最后Zygote进程fork出第一个进程:SystemServer进程,SystemServer主要完成了以下工作:

android app安装
首先这里我们先介绍一下PackageManagerService,其主要是完成Android中应用程序安装的服务,我们了解的Android应用程序安装的方式:
| 1 2 3 4 |
|

虽然安装方式不同,但是最后四种方式都是通过PackageManagerService服务来完成应用程序的安装。而PackageManagerService服务则通过与Installd服务通信,发送具体的指令来执行应用程序的安装、卸载等工作
| 1 2 3 4 5 6 |
|
应用程序在安装时涉及到如下几个重要目录:

我们了解完App的安装流程是由PackageManagerService,同理SystemServer启动了一个更加重要的服务ActivityManagerService, 而AMS其中很重要的一个作用就是启动Launcher进程,具体是怎么启动的,大家可以参考文章:Android系统启动流程(四)Launcher启动过程与系统启动流程,这里就不再详细讲解,而进入Launcher进程,我们就进入了App启动的流程。
(2)App启动流程
Android系统启动的最后一步是启动一个Home应用程序,这个应用程序用来显示系统中已经安装的应用程序,这个Home应用程序就叫做Launcher。应用程序Launcher在启动过程中会请求PackageManagerService返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,这样用户可以通过点击这些快捷图标来启动相应的应用程序
前面我们描述了AMS将Launcher启动,然后进入App启动流程,这里参考文章:ActivityThread的理解和APP的启动过程

| 1 2 3 4 5 6 7 8 |
|
到这里,我们的大致弄清了APP的启动流程,而这里我们就进入了加壳中十分重要的地方ActivityTread
(3)ActivityThread启动流程
寒冰大佬在FART:ART环境下基于主动调用的自动化脱壳方案 一文中讲述了ActivityThread.main()是进入App世界的大门,并由此展开了对加壳原理的讲述
同理接下来,我们开始进行源码分析,了解ActivityThread的具体操作:
xref/frameworks/base/core/java/android/app/ActivityThread.java

根据寒冰大佬描述,在ActivityThread完成实例化操作,调用thread.attach(false)完成一系列初始化准备工作,最后主线程进入消息循环,等待接收来自系统的消息。当收到系统发送来的bindapplication的进程间调用时,调用函数handlebindapplication来处理该请求
| 1 2 3 4 5 6 7 8 9 10 |
|
在处理消息过程,很很明显进入了handlebindapplication函数
这里我再用寒冰大佬文章的内容:

我们定位第四步,Application进行实例化,然后进入makeApplication

然后我们进入newApplication

这里我们可以看见完成了两件事:
| 1 2 |
|
然后我们继续进入Application.attach()函数

这里我们就进一步调用了attachBaseContext()方法
最后回到handlebindapplication中执行第6步,进入callApplicationOnCreate()函数

就执行了Application.onCreate()方法
总结:
| 1 2 3 4 |
|
这里我附上网上一个大佬的详细执行流程图:

2.整体加壳原理详解
(1)整体加壳原理
Dex整体加壳可以理解为在加密的源Apk程序外面有套上了一层外壳,简单过程为:


如何对App进行加一层外壳呢,这里就需要应用动态加载的原理,关于动态加载和类加载器,我在上篇文章中有详细讲解:Android加壳脱壳学习(1)——动态加载和类加载机制详解
这里我们可以用一个案例来进一步讲述,我们打开一个整体加壳的样本

我们很明显看见,除了一个代理类Application,其他相关的代码信息都无法发现

在代理类中反射调用了一些方法,很显然我们解析出的结果都无法查找,很明显就说明在Application.attchBaseContext()和Application.onCreate()中必须要完成对源加密的dex的动态加载和解密
结合上面的描述,App加载应用解析时就是这个流程:
| 1 2 3 4 5 6 |
|
(2)类加载器的修正
上面我们已经很清晰的了解了壳加载的流程,我们很明显的意识到一个问题,我们从头到尾都是用PathClassLoader来加载dex,而上篇文章我在讲类加载器的过程中说过

| 1 2 3 4 5 6 7 8 |
|
我们要想动态加载dex文件必须使用自定义的DexClassLoader,那我们直接使用DexClassLoader进行加载就可以么,很显然不行,还是会报异常
| 1 |
|
所以我们要想使用DexClassLoader进行动态加载dex,我们需要进行类加载器的修正
当前实现类加载器的修正,主要有两种方案:
| 1 2 |
|
<1>类加载器替换
怎么去替换系统的类加载器了,这就和我们上面分析的ActivityThread中LoadedApk有关了,LoadedApk主要负责加载一个Apk程序,我们进一步分析源码

很明显,我们可以想到我们通过反射获取mclassLoader,然后使用我们的DexClassLoader进行替换,不就可以成功的让DexClassLoader拥有生命周期了么
源码实现:
| 1 2 3 4 5 6 |
|
| 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 |
|
<2>类加载器插入
还有一种方案,动态加载中我们讲述了类加载器的双亲委派机制,就是说我们的类加载器刚拿到类,并不会直接进行加载,而是先判断自己是否加载,如果没有加载则给自己的父类,父类再给父类,所以我们让DexClassLoader成为PathClassLoader的父类,这样就可以解决DexClassLoader生命周期的问题
| 1 2 3 |
|
代码实现:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
完成壳加载器的修正后,我们就可以正常的加载dex了
三、整体加壳案例实现
前面我们详细讲述了App运行机制和整体加壳的实现机制,下面我们就按照前面的讲述,来实现一个简单的整体加壳案例
实验准备:
| 1 2 |
|
1.编写源程序

这就是我们的源程序,源程序运行,我们会在日志中看见我们打印的信息,然后我们生成dex文件
2.编写壳程序
(1)准备工作
将dex文件上传sdcard,并给应用设置存储权限


(2)编写代理类
我们首先编写代理类,模仿上面的加壳应用

然后我们设置AndroidManifest.xml中的代理类别

然后我们选择在attachBaseContext或onCreate中对我们的dex进行动态加载和类加载器修正即可,因为这里我们源dex并未进行加密,所以也无需解密的过程
然后加入导入类的Activity

(3)动态加载
我们进行动态加载classes.dex

然后使用上面的一种方法进行类加载器修正

然后运行

运行成功,说明我们的整体加壳成功
四、脱壳点相关概念详解
上面我们已经理解了APP加壳的基本原理,下面我们进一步来学习如何进行脱壳,Android APP脱壳绕不开DexFile、ArtMethod两个概念,这两个在脱壳中扮演的至关重要的地位,无数的脱壳点都是从其演变而来。
1.Dex加载流程
我们在分析脱壳点过程中,首先就需要明白Dex加载的基本流程

| 1 2 3 |
|
我们依次来分析这个过程中的源码
DexPathList
| 1 2 3 4 5 6 7 8 |
|
makeDexElements
| 1 2 3 4 5 6 |
|
loadDexFile
| 1 2 3 4 5 6 7 8 9 10 |
|
loadDex
| 1 2 3 4 |
|
DexFile
| 1 2 3 4 5 6 7 |
|
这里出现的mCookie,mCookie在C/C++层中是DexFile的指针,我们在下面详细讲解
openDexFile
| 1 2 3 4 5 6 7 8 9 10 11 |
|
这里就进入了C/C++层
openDexFileNative

为了节约篇幅,我们快速分析,中间再经过一些函数
| 1 2 3 4 |
|
最后进进入了Dex2Oat,这就进入了Dex2Oat的编译流程
反之如果我们在下面Dex2Oat的流程中通过Hook相关方法或execv或execve导致dex2oat失败,我们就会返回到OpenDexFilesFromOat
OpenDexFilesFromOat

会先在HasOriginalDexFiles里尝试加载我们的Dex,也就是说,倘若我们的壳阻断了dex2oat的编译流程,然后又调用了DexFile的Open函数。
DexFile::Open

校验dex的魔术字字段,然后调用DexFile::OpenFile
DexFile::OpenFile
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
OpenCommon

最后又再次回到DexFile类,这里我们的dex文件加载基本流程分析完毕
2.Dex2Oat编译流程
Dex2oat是google公司为了提高编译效率的一种机制,从Android8.0开始实施,一些加壳厂商实现抽取壳往往会禁用Dex2oat,而针对整体加壳没有禁用的Dex2Oat也成为了脱壳点

Exec
| 1 2 3 4 5 6 7 8 9 10 11 |
|
ExecAndReturnCode

而我们就可以通过Hook execv或execve来禁用Dex2Oat,而如果我们不禁用dex2oat,execve函数是用来调用dex2oat的二进制程序实现对dex文件的加载,我们这时候找到dex2oat.cc这个文件,找到main函数
| 1 2 3 4 5 6 7 |
|
这里我们调用了Dex2oat
Dex2Oat
| 1 2 3 4 5 6 7 8 9 10 11 12 |
|
Dex2oat中会对dex文件进行逐个类逐个函数的编译,setup()函数完成对dex的加载
然后顺序执行,就会进入CompileApp
编译过程中会按照逐个函数进行编译,就会进入CompileMethod

到这里Dex2oat的基本流程就分析完毕
3.类加载流程
要理解DexFile为什么如此重要,首先我们要清除Android APP的类加载流程。Android的类加载一般分为两类隐式加载和显式加载
| 1 2 3 4 5 6 7 8 9 |
|
我们详细看一下显示加载:
| 1 2 3 |
|
我们在详细来看一下在类加载过程中的流程:
java层

我们可以发现类加载中关键的DexFile,该类用来描述Dex文件,所以我们的脱壳对象就是DexFile
这里从DexFile进入Native层中,还有一个关键的字段就是mCookie

后面我们详细的介绍mCookie的作用
我们进一步分析,进入Native层
Native层
/art/runtime/native/[dalvik_system_DexFile.cc

| 1 |
|

通过这里的分析,我们可以知道mCooike转换为C/C++层指针后,就是dexfile的索引
我们继续分析DefineClass
| 1 2 3 4 5 6 7 8 9 10 11 |
|
LoadClass
| 1 2 3 4 5 6 7 8 9 10 11 |
|
LoadClassMembers
| 1 2 3 4 5 6 7 8 9 10 |
|
LoadMethod
| 1 2 3 4 5 6 |
|
LinkCode

我们可以发现这里就进入了从linkcode后就进入了解释器中,并对是否进行dex2oat进行了判断,我们直接进入解释器中继续分析
我们知道Art解释器分为两种:解释模式下和quick模式下,而我们又知道Android8.0开始进行dex2oat
| 1 2 3 |
|
所以一般的加壳厂商会禁用掉dex2oat,这样可以是所有的函数都运行在解释模式下,所以一些脱壳点选在dex2oat流程中,可能针对禁用dex2oat的情况并不使用,我们这里主要针对整体加壳,就不展开讲述,最后我们得知解释器中会运行在Execute下
Execute
| 1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
这里我们大致分析完成了类加载的思路
4.DexFile详解
前面我们分析了很多,对dex加载、类加载等都已经有了一个很详细的了解,而最终一切的核心就是DexFile,DexFile就是我们脱壳所关注的重点,寒冰大佬在拨云见日:安卓APP脱壳的本质以及如何快速发现ART下的脱壳点中提到,在ART下只要获得了DexFile对象,那么我们就可以得到该dex文件在内存中的起始地址和大小,进而完成脱壳。
我们先查看一些DexFile的结构体

只要我们能获得起始地址begin和大小size,就可以成功的将dex文件脱取下来,这里我们记得DexFile含有虚函数表,所以根据C++布局,要偏移一个指针
![]()
而DexFile类还给我们提供了方便的API

这样只要我们找到函数中有DexFile对象,就可以通过调用API来进一步dump dex文件,由此按照寒冰大佬的思想,大量的脱壳点由此产生
(1)直接查找法
我们通过直接在Android源码中搜索DexFile,就可以获得海量的脱壳点

我们通过在IDA中搜索libart.so导出的DexFile,同样可以获得大量的脱壳点

(2)间接查找法
这里就是寒冰大佬在文章中提到的通过ArtMethod对象的getDexFile()获取到ArtMethod所属的DexFile对象的这种一级间接法,通过Thread的getCurrentMethod()函数首先获取到ArtMethod或者通过ShadowFrame的getMethod获取到ArtMethod对象,然后再通过getDexFile获取到ArtMethod对象所属的DexFile的二级间接法。
| 1 2 |
|
5.ArtMethod详解
上面我们已经详细分析了DexFile的文件结构,我们知道通过ArtMethod可以获得DexFile,那么为啥又要单独提ArtMethod呢,因为ArtMethod在抽取壳和VMP等壳中扮演了重要的角色
ArtMethod结构体

我们通过ArtMethod可以获得codeitem的偏移和方法索引,熟悉dex结构的朋友知道codeitem就是代码实际的值,而codeitem则再后续加壳技术扮演了至关重要的地址,而且ArtMethod还有非常丰富的方法,可以帮助大家实现很多功能,所以在脱壳工作中也是十分重要的
五、脱壳技术归纳
前面分析了很多,最后无非整体加壳的脱壳方案落脚在DexFile的关键对象上,由此产生了一些常用的方法

1.现有工具脱壳法
工欲善其事必先利其器,整体加壳已经很多年,不少的大佬们都开发了很多非常好用的工具,我们在自己掌握原理过程时,平时工作中也可以使用很多大佬的开发工具,这里随便举几个自己经常用的工具,这里我对各个大佬的脱壳工具进行了一个梳理

(1)FRIDA-DEXDump
这是葫芦娃大佬开发的针对整体加壳的工具,主要通过frida技术,文章参考:深入 FRIDA-DEXDump 中的矛与盾,该工具的特点是一般的hook方案通过直接搜索DEX的头文件dex.035来定位dex的起始地址,但是后来不少公司对头文件的魔术字段进行了抹除,这样针对没有文件头的 DEX 文件,该工具通过map_off 找到 DEX 的 map_list, 通过解析它,并得到类型为 TYPE_MAP_LIST 的条目计算出文件的大小和起始地址,也很好的提供了一种解决思路。
使用方法:
FRIDA-DEXDump使用十分的简单,详细参考github:FRIDA-DEXDump
这里引用一张大佬星球的使用流程图,非常详细,快速进行脱壳

我们简单演示一下,这里结合objection一起使用

然后再次打开脱下来的dex,即可
(2)FDex2
Fdex2主要是利用Android7.0及版本以下的特殊API getDex()来进行脱壳,原本是基于Xposed的模块,不过掌握原理后,大家可以使用各种Hook框架去实现,参考链接:安卓xposed脱壳工具FDex2
(3)其他工具
针对整体壳的脱壳工具有很多,无非是针对各种脱壳点再采用不同的方法,其原理是殊途同归,而基于源码定制的Fart、youpk等等针对整体加壳壳都可以基本实现完全的脱壳,而且抽取壳也有着很好的效果,下面我们就依次来讲述具体的脱壳方法原理,各种脱壳工具如下图所示:

2.Hook脱壳法
我们前面知道了,只要函数中包含DexFile对象,我们就可以通过Hook技术拿到对象,然后取到begin和size,从而进行脱壳,市面上使用较多的无非是Xposed和frida,我平时使用frida较为方便,这里也用frida和大家演示:
首先我们使用GDA识别加壳程序

很明显是进行了整体加壳,有没其他加壳暂时不知道,我们先进行脱壳
找到脱壳点
通过IDA打开libart.so,搜索DexFile,我们可以找到海量的脱壳点
![]()
我们就随便找一个包含DexFile的脱壳函数,然后记录符号值

然后我们编写hook脚本

| 1 |
|
然后启动frida_server

附加进程进行dump,这里我们存在sdcard下面,所以需要提前赋予sdcard权限

这里就脱壳成功

然后我们打开相应的dex

此时说明我们整体脱壳成功,不过应用还有抽取壳,这个不是本文解决的内容
3.插桩脱壳法
插桩脱壳法,就是在Android源码里面定位到相应的脱壳点,然后插入相应的代码,重新编译源码生成系统镜像,最后就可以使用定制的系统进行脱壳
我们在源码编译(1)——Android6.0源码编译详解中已经讲述了如何编译源码,接下来我们进行插桩脱壳
同理、还是定位脱壳点,我们还是随便定位一个脱壳点LoadMethod 然后进行插桩

| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
同理我们在execute同样插桩此段代码,最后进行编译,编译成功

然后给程序授权sdcard权限,再次启动应用,就可以看见脱取的dex文件就保存在sdcard目录下

再次将sdcard下dex文件打开,这里我们已经看见了8732435这个文件,再次打开脱取成功

4.反射脱壳法
反射脱壳法的核心思想就是利用前面我们提到的mCooike值
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
综述mCookie是在native层就是dexfile的指针,我们利用反射原理来获取mCookie,从而就可以进行脱壳了,这里我们同样使用frida演示:
编写hook代码


我们看见了和上面同样大小的8841876_mCookie.dex

使用工具打开,发现同样脱壳成功

5.动态调试脱壳法
所谓动态调试法,核心原理和上面一样,就是我们在动态调试的过程中找到DexFile的起始地址和大小,然后执行脚本进行dump
首先选取脱壳点,我们还是选择DexFile::DexFile

动态调试的步骤我在前面的文章中已经做了详细的讲解,不会的朋友去看前面的文章
首先我们启动android_server

然后我们附加上进程



然后我们打开libart.so,并定位到DexFile::DexFile

然后在该函数下断点,然后F9过来

此处我们就可以很明显看到X1就是我们的起始地址,X4是我们的偏移值
编写脚本进行hook
| 1 2 3 4 5 6 7 8 9 10 11 |
|

直接运行run
然后我们查看dump.dex文件
![]()

我们可以发现这里是代理类,还没有到我们想要的dex,我们再次F9,再次到这里,地址再次改变,再次结合长度来计算,我们每次计算可以取小点值,先试一下

发现还是不是,我们需要不停测试直到dump出dex为此
这里大家可以下去按照此方法尝试,或者换一个脱壳点来尝试
6.特殊API脱壳法
所谓特殊的API脱壳法就是通过Android自身提供的API来获得Dex,这主要是参考Fdex2,前面我们讲了Fdex2主要是利用Android7.0及以下提供了getDex()和getBytes()两个API,我们可以直接可以获得class对象,然后直接调用这两个API


编写hook代码:

| 1 2 3 4 |
|
然后我们查看程序的类对象,随便dump一个类对象


然后我们再次用工具打开


发现就可以成功的dump
通过这种方式,我们发现神奇的事我们还可以抽取壳的情况,比如我们之前为空类

我们明显可以发现这里是采用了函数抽取的技术,一般的一代壳dump方案是无法解决抽取壳的,我们使用特殊API方法

再次打开,成功dump

这其实主要是抽取壳的一个回填时机的问题,这个详细放在以后抽取壳中讲解
六、实验总结
本文总结了当下dex整体加壳的基本原理,和常用的一些脱壳方案,并一一进行复现,还有一些文件监控法等,由于我平时用的很少就没列举了,复现实验过程中由于涉及到不同的实验,所以我用了Android 6.0 Android 7.0 Android 8.0三台机器进行实验,所以大家可以注意下对应的方法和其Android版本,这里彻底解决了整体加壳的脱壳方案,到这里可以掌握脱壳、抓包、Hook、反Hook、反调、反签等基本手段,这样在进行Android App漏洞挖掘过程中将事半功倍。后面我将继续讲解Android App漏洞中的XSS漏洞、Sql注入漏洞、文件上传漏洞、端口扫描漏洞、WebView漏洞等。
脱壳脚本相关样本会放在github,所有的脱壳脚本和工具和上传知识星球
github:github
七、参考文献
| 1 2 3 4 |
|
相关文章:
Android漏洞之战——整体加壳原理和脱壳技巧详解
一、前言 为了帮助更加方便的进行漏洞挖掘工作,前面我们通过了几篇文章详解的给大家介绍了动态调试技术、过反调试技术、Hook技术、过反Hook技术、抓包技术等,掌握了这些可以很方便的开展App漏洞挖掘工作,而最后我们还需要掌握一定的脱壳技巧…...
网络
mcq Java 传输层:拆分和组装,完成端到端的消息传递,流量控制,差错控制等 网络层: 寻址、路由,复用,拥塞控制,完成源到宿的传递。 显然A选项是错误的,有流量控制的是传输层…...
一直往下get的map
一直往下get的map 文档:一直往下get的map.note 链接:http://note.youdao.com/noteshare?id7b6d315d86ce9e5f8d7cac9be8e924b8&sub95F9FFDA8EB447BBA506286E261F4C88 添加链接描述 package com.example.demo.entity;import org.bson.Document; impo…...
Azure如何调整虚拟机的大小
参考 https://blog.csdn.net/m0_48468018/article/details/132267096 创建虚拟机进入资源,点击大小选项,并对大小进行调整 点击如下图的cloud shell,进入Azure CLI,使用az vm resize 进行大小调整 命令中的g对应资源组,n对应虚拟机名称&am…...
stm32F103R6实现流水灯参考源代码
#include "main.h" #include "gpio.h" void SystemClock_Config(void); void sleep(int a) {int i0,j0;for(i0;i<a;i){for(j0;j<2000;j);}} 真正发挥效果的是这个main函数// int main(void) {int i0;HAL_Init();SystemClock_Config();MX_GPIO_Init()…...
blender 发射体粒子
发射体粒子的基础设置 选择需要添加粒子的物体,点击右侧粒子属性,在属性面板中,点击加号,物体表面会出现很多小点点,点击空格键,粒子会自动运动,像下雨一样; bender 粒子系统分为两…...
你真的掌握了 Python 的七种参数了吗?
不知道为什么网上总有人说 Python 的参数类型有 4 种啊,5 种啊,殊不知其实有 7 种。Python 的 7 种参数分别是 默认参数、位置参数、关键字参数、可变长位置参数、可变长关键字参数、仅位置参数 和 仅关键字参数。小白可能没见过“可变长参数”ÿ…...
人大进仓数据库ksql命令基础
测试环境信息: 系统为银河麒麟V10 数据库为Kingbase ES V8 数据库安装目录为/opt/Kingbase/ES/V8 ksql命令位于/opt/Kingbase/ES/V8/Server/bin下 使用--help获取帮助 续上图 1.查看数据库列表 ./ksql -U system -l 2.查看数据库版本 ./ksql -V 3.连接指定的数据库tes…...
网站上的网页,无法通过百度和bing搜索引擎来搜索
最近搜索某公司网站上的技术资料,百度/bing都不能工作,纳闷 看了下该网站的robots.txt 明白了 User-Agent: * Disallow: / 参考: 网站 robots.txt 文件配置方法,如何禁止搜索引擎收录指定网页内容 - 知乎...
Redis与MySQL的比较:什么情况下使用Redis更合适?什么情况下使用MySQL更合适?
Redis和MySQL是两种不同类型的数据库,各有自己的特点和适用场景。下面是Redis和MySQL的比较以及它们适合使用的情况: Redis适合的场景: 高性能读写:Redis是基于内存的快速Key-Value存储,读写性能非常高。它适用于需要…...
34_windows环境debug Nginx 源码-配置WSL和CLion
文章目录 WSL 中安装 编译构建使用的相关软件重装默认的 ssh创建 libstdc++.so 软链接34_windows环境debug Nginx 源码-配置WSL和CLionWSL 中安装 编译构建使用的相关软件 sudo apt-get update sudo apt-get install libstdc++6 dpkg -L libstdc++6sudo apt-get install libpc…...
单词倒排(C语言详解)
题目:单词倒排 描述:对字符串中的所有单词进行倒排。 说明: 1、构成单词的字符只有26个大写或小写英文字母; 2、非构成单词的字符均视为单词间隔符; 3、要求倒排后的单词间隔符以一个空格表示;如果原字…...
一、数学建模之线性规划篇
1.定义 2.例题 3.使用软件及解题 一、定义 1.线性规划(Linear Programming,简称LP)是一种数学优化技术,线性规划作为运筹学的一个重要分支,专门研究在给定一组线性约束条件下,如何找到一个最优的决策&…...
【推荐】深入浅出学习Spring框架【中】
目录 1.AOP是什么? 2.案列: 3.spring的aop的专业术语 4.代码模拟 4.1 前置通知 3.2.后置通知 3.3.环绕通知 3.4.异常通知 3.5.过滤通知 1.AOP是什么? 面向切面编程(Aspect-Oriented Programming)是一种编程范式,它的主要…...
使用 HTML、CSS 和 JavaScript 创建多步骤表单
使用 HTML、CSS 和 JavaScript 创建多步骤表单 为了处理又长又复杂的表单,我们需要将它们分成多个步骤。通过一次只在屏幕上显示一些输入,表单会感觉更容易理解,并防止用户感到被大量的表单字段淹没。 在本文中,我将逐步指导如何…...
C语言笔试训练【第九天】
文章目录 👿1、下列程序的输出是( )💎2、二维数组X按行顺序存储,其中每个元素占1个存储单元。若 X[4][4] 的存储地址为 Oxf8b82140 , X[9][9] 的存储地址为 Oxf8b8221c ,则 X[7][7] 的存储地址为( …...
左邻右舍裂差法求和 以及 连续自然数的立方和公式
左邻右舍裂差法求和 1 2 2 3 3 4 4 5 . . . n ( n 1 ) ? 1\times22\times33\times44\times5...n\times(n1)? 12233445...n(n1)? 看成数列 a n n 2 n , ( n ∈ N ) a_nn^2n, (n\in N^) ann2n,(n∈N) 的前 n n n 项和 S n S_n Sn. 原理:将…...
阿里云故障洞察提效 50%,全栈可观测建设有哪些技术要点?
本文根据作者在「TakinTalks 稳定性社区 」公开分享整理而成 #一分钟精华速览# 全栈可观测是一种更全面、更综合和更深入的观测能力,能协助全面了解和监测系统的各个层面和组件,它不仅仅是一个技术上的概念,更多地是技术与业务的结合。在“…...
docker run 命令30个常用参数详解
文章目录 0.前言docker run 命令示例 2.Docker run 多种用法知其然知其所以然1. 基本用法2. 启动交互式容器3. 映射端口4. 挂载文件/目录5. 设置环境变量6. 指定容器名称7. 后台运行容器8. 重启策略9. 其他参数 2. docker run 命令参数详解1. -d:以后台模式…...
[kali]kali linux镜像下载地址
百度网盘地址 链接:https://pan.baidu.com/s/1cxySSyQdLIkox-w_CSka4Q 提取码:cevu 官方下载合集 https://www.kali.org/downloads/(所有版本) 独立链接: 2020.3版本 64位:https://cdimage.kali.org/kali-2020.…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
