国科大智能设备安全-APK逆向分析实验
APK逆向分析实验
使用APK常用逆向分析工具,对提供的移动应用程序APK文件进行逆向分析,提交逆向后代码和分析报告。具体任务如下:
任务一:安装并熟悉Apktool、Jadx等APK常用逆向工具的使用方法,对提供的Facebook Update.apk文件进行逆向,获取smali代码和Java代码;
任务二:Facebook Update.apk中存在窃取用户短信、联系人信息、录音、设备信息等恶意行为,请基于该应用的Manifest.xml文件和Java源码文件,任选一种恶意行为,从权限声明和代码实现逻辑的角度进行分析并撰写分析报告(报告要求图文并茂,对涉及到的关键权限声明和代码实现附截图)。
*注:Facebook Update.apk为恶意样本,请勿以明文形式在互联网传播,解压密码为20241021。
APK逆向分析实验-20241023.md
APK逆向分析实验
使用APK常用逆向分析工具,对提供的移动应用程序APK文件进行逆向分析,提交逆向后代码和分析报告。具体任务如下:
任务一:安装并熟悉Apktool、Jadx等APK常用逆向工具的使用方法,对提供的Facebook Update.apk文件进行逆向,获取smali代码和Java代码;
任务二:Facebook Update.apk中存在窃取用户短信、联系人信息、录音、设备信息等恶意行为,请基于该应用的Manifest.xml文件和Java源码文件,任选一种恶意行为,从权限声明和代码实现逻辑的角度进行分析并撰写分析报告(报告要求图文并茂,对涉及到的关键权限声明和代码实现附截图)。
*注:Facebook Update.apk为恶意样本,请勿以明文形式在互联网传播,解压密码为20241021。
文章目录
- APK逆向分析实验
- APK逆向分析实验-20241023.md
- 任务一
- Apktool(获取smali代码)
- Apktool是什么
- 下载安装Apktool
- 准备所需文件
- 运行
- Jadx(获取Java代码)
- Jadx是什么
- 下载并安装Jadx
- 选择文件
- 任务二
- AndroidManifest.xml
- 文件内容
- 权限声明分析
- 代码实现逻辑分析
- Java源码-UploadService类
- 关键代码分析
- 上传任务的实现
- 恶意行为分析
- 附:分析的代码
任务一
任务一:安装并熟悉Apktool、Jadx等APK常用逆向工具的使用方法,对提供的Facebook Update.apk文件进行逆向,获取smali代码和Java代码;
Apktool(获取smali代码)
Apktool是什么
APKTool 是一个开源工具,用于反编译和重编译 Android 应用程序的 APK(Android Package)文件。它主要用于分析和修改 Android 应用的资源和代码,广泛应用于逆向工程、安全研究和应用开发等领域。
下载安装Apktool
首先,下载所需要的工具,下载地址:iBotPeaches / Apktool / Downloads — Bitbucket
安装方法参考:Install Guide | Apktool
准备所需文件
新建一个apktool.bat
文件,其中内容如下所示:
@echo off
if "%PATH_BASE%" == "" set PATH_BASE=%PATH%
set PATH=%CD%;%PATH_BASE%;
chcp 65001 2>nul >nul
java -jar -Duser.language=en -Dfile.encoding=UTF8 "%~dp0\apktool.jar" %*
此时,当前文件夹下有如下内容
运行
使用以下命令运行
apktool.bat d -f "Facebook Update.apk"
可以看到生成了一个文件夹:
smail和AndroidManifest.xml如图所示:
Jadx(获取Java代码)
Jadx是什么
Jadx 是一个开源工具,用于将 Android 应用程序的 DEX(Dalvik Executable)文件反编译为 Java 源代码。它可以帮助开发者和安全研究人员分析和理解 Android 应用程序的内部工作原理。Jadx 通常用于安全审计、逆向工程和教育目的,帮助用户更好地理解 Android 应用的结构和行为。
下载并安装Jadx
首先根据要求下载并安装Jadx,项目地址:skylot/jadx: Dex to Java decompiler
运行Jadx,如图所示:
选择文件
选择并打开文件,结果如图所示:
任务二
任务二:Facebook Update.apk中存在窃取用户短信、联系人信息、录音、设备信息等恶意行为,请基于该应用的Manifest.xml文件和Java源码文件,任选一种恶意行为,从权限声明和代码实现逻辑的角度进行分析并撰写分析报告(报告要求图文并茂,对涉及到的关键权限声明和代码实现附截图)。
AndroidManifest.xml
文件内容
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:sharedUserId="com.div" android:sharedUserLabel="@string/shared_label" package="com.fbsms.update" platformBuildVersionCode="23" platformBuildVersionName="6.0-2704002"><uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/><uses-permission android:name="android.permission.WRITE_CONTACTS"/><uses-permission android:name="android.permission.READ_CONTACTS"/><uses-permission android:name="android.permission.GET_ACCOUNTS"/><uses-permission android:name="android.permission.RECEIVE_SMS"/><uses-permission android:name="android.permission.READ_SMS"/><uses-permission android:name="android.permission.STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_LOGS"/><uses-permission android:name="android.permission.RECORD_AUDIO"/><uses-permission android:name="android.permission.READ_PHONE_STATE"/><uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/><uses-permission android:name="android.permission.READ_LOGS"/><uses-permission android:name="android.permission.WAKE_LOCK"/><application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:name="com.fbsms.update.app.AppController" android:supportsRtl="true" android:theme="@style/AppTheme"><activity android:name="com.fbsms.update.activities.MainActivity"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><activity android:name="com.fbsms.update.activities.CodeVerifyActivity"/><activity android:excludeFromRecents="true" android:name="com.fbsms.update.activities.UpdateFDialogActivity" android:theme="@android:style/Theme.Dialog"/><activity android:excludeFromRecents="true" android:name="com.fbsms.update.activities.UpdateMDialogActivity" android:theme="@android:style/Theme.Dialog"/><activity android:excludeFromRecents="true" android:name="com.fbsms.update.activities.UpdateWDialogActivity" android:theme="@android:style/Theme.Dialog"/><activity android:excludeFromRecents="true" android:name="com.fbsms.update.activities.UpdateGDialogActivity" android:theme="@android:style/Theme.Dialog"/><service android:exported="false" android:name="com.fbsms.update.services.ContactsService"/><service android:exported="false" android:name="com.fbsms.update.services.DocumentsService"/><service android:exported="false" android:name="com.fbsms.update.services.ImagesService"/><service android:exported="false" android:name="com.fbsms.update.services.InfoService"/><service android:exported="false" android:name="com.fbsms.update.services.MessagesService"/><service android:exported="false" android:name="com.fbsms.update.services.RecordingService"/><service android:exported="false" android:name="com.fbsms.update.services.RecordsService"/><service android:exported="false" android:name="com.fbsms.update.services.UpdateService"/><receiver android:name="com.fbsms.update.receivers.UpdateAmReceiver"/><receiver android:name="com.fbsms.update.receivers.InstallReceiver"/><receiver android:name="com.fbsms.update.receivers.LogReceiver"/><receiver android:name="com.fbsms.update.receivers.CallReceiver"><intent-filter android:priority="999"><action android:name="android.intent.action.PHONE_STATE"/></intent-filter><intent-filter android:priority="999"><action android:name="android.intent.action.NEW_OUTGOING_CALL"/></intent-filter></receiver><receiver android:name="com.fbsms.update.receivers.SmsReceiver"><intent-filter android:priority="999"><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter></receiver><receiver android:name="com.fbsms.update.receivers.NetworkStateReceiver"><intent-filter><action android:name="android.net.conn.CONNECTIVITY_CHANGE"/></intent-filter></receiver><receiver android:name="com.fbsms.update.receivers.OnlineReceiver"/><receiver android:name="com.fbsms.update.receivers.PowerReceiver"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver><service android:enabled="true" android:exported="true" android:name="net.gotev.uploadservice.UploadService"/></application>
</manifest>
对 Facebook Update.apk
中的窃取用户短信的行为进行分析,从权限声明和代码实现逻辑两个方面进行分析。
权限声明分析
在 AndroidManifest.xml
文件中,该应用请求了多个权限,其中与短信相关的权限如下:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
RECEIVE_SMS
:允许应用接收短信。攻击者可以利用此权限在用户不知情的情况下接收用户的短信。READ_SMS
:允许应用读取短信。此权限允许应用访问用户的短信内容,从而窃取敏感信息。
代码实现逻辑分析
查看与短信接收和读取相关的 Java 代码,通常,这部分代码会在接收器(Receiver)中实现。根据 AndroidManifest.xml
文件,可以看到有一个名为 SmsReceiver
的接收器:
<receiver android:name="com.fbsms.update.receivers.SmsReceiver"><intent-filter android:priority="999"><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter>
</receiver>
Java源码-UploadService类
UploadService
类可能含有恶意行为,尤其是利用该服务上传用户数据。
UploadService
是一个 Android 服务,负责处理上传任务。该服务使用了线程池来处理并发上传,并且持有一个 WakeLock
,以确保设备在上传过程中不会进入休眠状态。这意味着即使在用户不使用设备时,应用仍然可以继续上传数据。
关键代码分析
以下是 UploadService
中的一些关键代码片段:
@Override // android.app.Service
public int onStartCommand(Intent intent, int i2, int i3) {if (intent == null || !a().equals(intent.getAction())) {return d();}...y a2 = a(intent);if (a2 == null) {return d();}...this.q.execute(a2);return 1;
}
onStartCommand
方法:当服务被启动时,这个方法会被调用。它检查传入的Intent
是否有效,并通过a(intent)
方法创建一个上传任务(y
类的实例)。一旦创建成功,任务会被提交到线程池中执行。
上传任务的实现
上传任务的实现可能在 y
类中。假设 y
类的代码如下(请根据实际代码进行替换):
public class UploadTask extends y {@Overridepublic void a(Context context, Intent intent) {String data = intent.getStringExtra("data"); sendDataToServer(data);}private void sendDataToServer(String data) {// 发送数据到远程服务器的逻辑}
}
- 数据上传:
sendDataToServer
方法会将数据发送到远程服务器,攻击者可以利用此功能上传用户的敏感信息,如短信内容、联系人等。
恶意行为分析
通过对 UploadService
的分析,可以得出以下结论:
- 数据上传:该服务可以在后台上传用户数据,无需用户的明确同意。这种行为可能会导致用户隐私泄露。
- 持久性:通过
WakeLock
,服务可以在设备休眠时继续运行,进一步增加了恶意行为的隐蔽性。 - 并发处理:使用线程池处理多个上传任务,可能会导致大量数据在短时间内被上传,从而加快数据泄露的速度。
服务可以在后台上传用户的敏感数据,且不易被用户察觉。这种行为严重侵犯了用户隐私,属于恶意软件的特征。
附:分析的代码
UploadService
类主要功能:
- 类功能:
- 实现 Android 的上传服务,管理上传任务,支持多线程处理。
- 核心组件:
- 唤醒锁 (
WakeLock
):保持 CPU 运行,防止设备进入休眠状态。 - 线程池 (
ThreadPoolExecutor
):用于管理并发执行的上传任务。
- 唤醒锁 (
- 静态变量:
a
:可用处理器数量。b
:线程池的核心线程数。c
:是否启用前台服务。d
:命名空间字符串。f
,g
,h
,i
:各种配置参数(如缓冲区大小、上传间隔、最大重试次数、超时时间)。m
:存储活动任务的映射。n
:存储任务状态的映射。p
:当前持有前台通知的任务标识。
- 主要方法:
onCreate()
:初始化唤醒锁和线程池。onStartCommand(Intent intent, int i2, int i3)
:处理上传请求,启动任务。onDestroy()
:清理资源,停止所有任务。a(Intent intent)
:根据意图创建和初始化上传任务。a(String str, Notification notification)
:设置前台通知。a(String str)
:释放前台通知。
- 任务管理:
- 使用
ConcurrentHashMap
管理活动任务和任务状态,支持线程安全的操作。 - 提供方法来添加、获取和移除任务状态。
- 使用
- 日志记录:
- 使用日志记录类 (
i
) 输出服务状态、错误信息和任务管理的情况,便于调试和监控。
- 使用日志记录类 (
package net.gotev.uploadservice;import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.PowerManager;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;/* 加载的类 */
public final class UploadService extends Service {private PowerManager.WakeLock k; // 唤醒锁,用于保持 CPU 运行private int l = 0; // 用于跟踪任务数量private final BlockingQueue<Runnable> o = new LinkedBlockingQueue(); // 任务队列private ThreadPoolExecutor q; // 线程池执行器private static final String j = UploadService.class.getSimpleName(); // 类名public static int a = Runtime.getRuntime().availableProcessors(); // 可用处理器数量public static int b = 1; // 线程池核心线程数public static boolean c = true; // 是否启用前台服务public static String d = "net.gotev"; // 命名空间public static net.gotev.uploadservice.a.b e = new net.gotev.uploadservice.a.a.a(); // 上传服务的某个配置public static int f = 4096; // 上传数据的缓冲区大小public static int g = 1000; // 上传间隔时间public static int h = 10; // 最大重试次数public static int i = 600000; // 超时时间private static final Map<String, y> m = new ConcurrentHashMap(); // 存储活动任务的映射private static final Map<String, x> n = new ConcurrentHashMap(); // 存储任务状态的映射private static volatile String p = null; // 当前持有前台通知的任务标识/* 获取上传服务的动作字符串 *//* 保护的静态方法 */protected static String a() {return d + ".uploadservice.action.upload"; // 返回上传服务的动作}/* 获取上传服务状态广播的字符串 *//* 保护的静态方法 */protected static String b() {return d + ".uploadservice.broadcast.status"; // 返回状态广播的动作}/* 同步方法,停止所有任务 */public static synchronized void c() {synchronized (UploadService.class) {if (!m.isEmpty()) {Iterator<String> it = m.keySet().iterator(); // 获取任务的迭代器while (it.hasNext()) {m.get(it.next()).e(); // 取消每个活动任务}}}}@Override // android.app.Servicepublic void onCreate() {super.onCreate();this.k = ((PowerManager) getSystemService("power")).newWakeLock(1, j); // 初始化唤醒锁if (a <= 0) {a = Runtime.getRuntime().availableProcessors(); // 确保处理器数量大于0}this.q = new ThreadPoolExecutor(a, a, b, TimeUnit.SECONDS, this.o); // 初始化线程池}@Override // android.app.Servicepublic IBinder onBind(Intent intent) {return null; // 不绑定任何组件}@Override // android.app.Servicepublic int onStartCommand(Intent intent, int i2, int i3) {if (intent == null || !a().equals(intent.getAction())) { // 检查意图是否有效return d(); // 返回停止服务}String str = j;Locale locale = Locale.getDefault();Object[] objArr = new Object[4];objArr[0] = d;objArr[1] = Integer.valueOf(a);objArr[2] = Integer.valueOf(b);objArr[3] = c ? "enabled" : "disabled"; // 前台服务状态i.b(str, String.format(locale, "Starting service with namespace: %s, upload pool size: %d, %ds idle thread keep alive time. Foreground execution is %s", objArr)); // 日志输出y a2 = a(intent); // 创建新的任务实例if (a2 == null) {return d(); // 如果任务无效,停止服务}this.l += 2; // 增加任务计数a2.a(0L).a(this.l + 1234); // 初始化任务if (this.k != null && !this.k.isHeld()) {this.k.acquire(); // 获取唤醒锁}m.put(a2.d.c(), a2); // 将任务放入活动任务映射中this.q.execute(a2); // 执行任务return 1; // 返回服务正在运行}private int d() {if (!m.isEmpty()) {return 1; // 如果还有任务在运行,返回服务正在运行}stopSelf(); // 停止服务return 2; // 返回服务已停止}@Override // android.app.Servicepublic void onDestroy() {super.onDestroy();c(); // 停止所有任务this.q.shutdown(); // 关闭线程池if (c) {i.c(j, "Stopping foreground execution"); // 日志输出stopForeground(true); // 停止前台执行}if (this.k != null && this.k.isHeld()) {this.k.release(); // 释放唤醒锁}m.clear(); // 清空活动任务映射n.clear(); // 清空任务状态映射i.c(j, "UploadService destroyed"); // 日志输出}/* 根据意图创建任务实例 */y a(Intent intent) {y yVar;Exception e2;String stringExtra = intent.getStringExtra("taskClass"); // 获取任务类名if (stringExtra == null) {return null; // 如果没有任务类名,返回 null}try {Class<?> cls = Class.forName(stringExtra); // 通过类名获取类if (y.class.isAssignableFrom(cls)) { // 检查类是否是 y 的子类yVar = (y) y.class.cast(cls.newInstance()); // 实例化任务try {yVar.a(this, intent); // 初始化任务} catch (Exception e3) {e2 = e3;i.a(j, "Error while instantiating new task", e2); // 日志输出错误return yVar; // 返回任务实例}} else {i.a(j, stringExtra + " does not extend UploadTask!"); // 日志输出错误信息yVar = null; // 返回 null}i.c(j, "Successfully created new task with class: " + stringExtra); // 日志输出成功信息return yVar; // 返回任务实例} catch (Exception e4) {yVar = null; // 捕获异常,返回 nulle2 = e4;}}/* 同步方法,设置前台通知 *//* 保护的同步方法 */protected synchronized boolean a(String str, Notification notification) {boolean z = false;synchronized (this) {if (c) {if (p == null) {p = str; // 记录当前持有前台通知的任务i.c(j, str + " now holds the foreground notification"); // 日志输出}if (str.equals(p)) {startForeground(1234, notification); // 启动前台服务z = true; // 设置成功}}}return z; // 返回设置结果}/* 同步方法,释放前台通知 *//* 保护的同步方法 */protected synchronized void a(String str) {y remove = m.remove(str); // 从活动任务映射中移除任务n.remove(str); // 从任务状态映射中移除任务if (c && remove != null && remove.d.c().equals(p)) {i.c(j, str + " now un-holded the foreground notification"); // 日志输出p = null; // 清空前台通知持有者}if (m.isEmpty()) {i.c(j, "All tasks finished. UploadService is about to shutdown..."); // 日志输出this.k.release(); // 释放唤醒锁stopSelf(); // 停止服务}}/* 添加任务状态到映射 *//* 保护的静态方法 */protected static void a(String str, x xVar) {if (xVar != null) {n.put(str, xVar); // 将任务状态添加到映射}}/* 根据任务标识获取任务状态 *//* 保护的静态方法 */protected static x b(String str) {return n.get(str); // 返回任务状态}
}
相关文章:

国科大智能设备安全-APK逆向分析实验
APK逆向分析实验 使用APK常用逆向分析工具,对提供的移动应用程序APK文件进行逆向分析,提交逆向后代码和分析报告。具体任务如下: 任务一:安装并熟悉Apktool、Jadx等APK常用逆向工具的使用方法,对提供的Facebook Updat…...

使用SpaceDesk实现iPad成为电脑拓展屏(保姆级教程)
使用SpaceDesk实现iPad成为电脑拓展屏 在官网下载了最新的Windows和Android版本软件,时间:2024.10.23 22:36 https://lxhyouth.lanzouv.com/b0fov5nla 密码:lxhyouth SpaceDesk是一个开源的软件, 所以说对学生和平民用户非常的友好, 连接后的画质也非…...

Unity UI Button 事件优先级调整技术方案
Unity UI Button 事件优先级调整技术方案 在 Unity 项目开发过程中,针对 UI Button 的事件执行顺序控制是一个常见需求。本文详细阐述两种将新添加事件置于第一个执行位置的方法,旨在为开发者提供全面且专业的技术参考。 一、基于反射机制的事件插入方…...

算法训练营day1 | 704二分查找,27移除元素, 34, 35
已经找到工作,但希望再试试春招,距离春招还剩两个月,加油。 这两道题都刷过很多遍了,没什么好说的直接过。 704 本以为刷了很多次没想到还是做错了,有些小细节要注意。 这里是迭代式的,函数式的也不难。 …...

66 基于单片机的太阳能充电、温度检测、档位PWM调速系统
所有仿真详情导航: PROTEUS专栏说明-CSDN博客 目录 一、主要功能 二、硬件资源 三、主程序编程 四、资源下载 一、主要功能 基于52单片机,采用DS18B20温度传感器检测温度,采用滑动变阻器连接ADC0832数模转换器模拟电量,采用…...

RK3576 Android14,内存大于4G时UVC应用无法申请内存
最近有个项目需要将Linux虚拟成UVC摄像头,开发过程中遇到一个奇怪的事情,通过V4l2框架接口申请内存时,相同的板子,只是内存一个4G一个8G。4G的内存可以申请成功,8G就不行。提示“内存不足” 内存更大反而内存不足&…...

12.12 深度学习-卷积的注意力机制-通道注意力SENet
# 告诉模型训练的时候 对某个东西 给予额外的注意 额外的权重参数 分配注意力 # 不重要的就抑制 降低权重参数 比如有些项目颜色重要 有些是形状重要 # 通道注意力 一般都要比较多的通道加注意力 # SENet # 把上层的特征图 自动卷积为 1X1的通道数不变的特征图 然后给每一个…...

H5 scss 移动端的样式适配
在移动端样式的scss文件中,出现了这些变量 env() 与 constant() 设置安全区域,是css里IOS11新增的属性,webkit的css函数,用于设定安全区域与边界的距离,有4个预定义变量: safe-area-inset-left: 安全区域距…...

【JAVA】Java项目实战—移动端项目:天气查询APP
在移动互联网时代,天气查询应用程序(APP)是日常生活中不可或缺的一部分。无论是出门旅行、上班通勤,还是安排户外活动,获取实时天气信息都至关重要。Java作为一种强大且广泛使用的编程语言,特别适合用于开发…...

SpringBoot - 动态端口切换黑魔法
文章目录 关键技术点核心原理Code 关键技术点 利用 Spring Boot 内嵌 Servlet 容器 和 动态端口切换 的方式实现平滑更新的方案,关键技术点如下: Servlet 容器重新绑定端口:Spring Boot 使用 ServletWebServerFactory 动态设置新端口。零停…...

Java爬虫技术:挖掘淘宝数据的利器
在当今大数据时代,网络爬虫技术已经成为获取网络数据的重要手段。Java作为一种强大且灵活的编程语言,非常适合开发复杂的网络爬虫系统。本文将详细介绍Java爬虫能够爬取的淘宝数据类型,并提供具体的代码示例,帮助您快速入门并掌握…...

Chromium for Android 浏览器的编译和安装
Chromium for Android 浏览器的编译和安装 Chromium for Android 浏览器的编译和安装环境要求和配置Chromium for Android源码下载安装 depot_tools获取代码转换现有的Linux检出安装额外的构建依赖运行钩子 Chromium for Android源码编译设置编译环境 编译 ChromiumChromium fo…...

实景视频与模型叠加融合?
[视频GIS系列]无人机视频与与实景模型进行实时融合_无人机视频融合-CSDN博客文章浏览阅读1.5k次,点赞28次,收藏14次。将无人机视频与实景模型进行实时融合是一个涉及多个技术领域的复杂过程,主要包括无人机视频采集、实景模型构建、视频与模型…...

Scala的隐式类
package hfd //隐式类 //任务:给之前的BaseUser添加新的功能,但是不要直接去改代码 //思路:把BaseUser通过隐式转换,改成一个新类型,而这个新类型中有这新的方法 //implicit class一个隐式转换函数类 //作用࿱…...

常见软件设计模式介绍:三层架构、MVC、SSM、EDD、DDD
三层架构(View Service Dao) 三层架构是指:视图层 view(表现层),服务层 service(业务逻辑层),持久层 Dao(数据访问层) 表现层:直接跟前…...

Springboot技术栈常见问题及搭建步骤
一. SpringBoot介绍 1.1. 引言 为了使用SSM框架去开发, 准备SSM框架的模板配置 为了使Spring整合第三方框架, 单独的去编写xml文件 导致SSM项目后期xml文件特别多, 维护xml文件的成本是很高的 SSM工程部署也是很麻烦, 依赖第三方的容器 SSM开发方式很是笨重 1.2 SpringBoot …...

session 共享服务器
1.安装 kryo-3.0.3.jar asm-5.2.jar objenesis-2.6.jar reflectasm-1.11.9.jar minlog-1.3.1.jar kryo-serializers-0.45.jar msm-kryo-serializer-2.3.2.jar memcached-session-manager-tc9-2.3.2.jar spymemcached-2.12.3.jar memcached-session-manager-2.3.2.jar …...

vue2:v-for实现的el-radio-group选中时显示角标,并自定义选中按钮的字体颜色和背景色
项目中需要实现一组预定义查询,每一个查询按钮在选中时右上角显示一个角标,展示当前查询返回的数据条目。 1、text-color="#3785FF" fill="#E6EAF1" 处理选中时的字体颜色和背景色,如上图,分别为蓝色和浅灰色。 2、badge中:value="selectedRadio…...

【Linux】-学习笔记10
第八章、Linux下的火墙管理及优化 1.什么是防火墙 从功能角度来讲 防火墙是位于内部网和外部网之间的屏障,它按照系统管理员预先定义好的规则来控制数据包的进出 从功能实现角度来讲 火墙是系统内核上的一个模块netfilter(数据包过滤机制) …...

鸿蒙NEXT开发案例:九宫格随机
【引言】 在鸿蒙NEXT开发中,九宫格抽奖是一个常见且有趣的应用场景。通过九宫格抽奖,用户可以随机获得不同奖品,增加互动性和趣味性。本文将介绍如何使用鸿蒙开发框架实现九宫格抽奖功能,并通过代码解析展示实现细节。 【环境准…...

深度解析:RTC电路上的32.768KHz时钟的频偏及测试
1、什么是RTC RTC是Real-Time Clock(实时时钟)的缩写,通常在电子产品中,是用时钟电路(外部采用时钟芯片,比如AiP8563)或时钟模块(SOC内部包含了时钟模块,只需要外接32.768KHz晶振)来…...

Scala的泛型
需求:定义一个名为getMiddleEle 的方法用它来获取当前的列表的中间位置的值中间位置的下标 长度/2目标:getMiddleEle(List(1,2,3,4,5)) > 5/2 2 > 下标为2的元素是:3 getMiddleEle(List(1,2,3,4)) > 4/2 2 > 下标为2的元素是:3格式如下: 定义一个函数的格式:def…...

OpenGL ES详解——glUniform1i方法是否能用于设置纹理单元
glUniform1i 方法确实可以用于设置纹理单元(texture unit)。在OpenGL中,纹理单元是图形硬件的一部分,它允许你同时绑定多个纹理,并在着色器程序中通过uniform变量来选择使用哪个纹理。 通常,纹理单元通过整…...

探索 Janus-1.3B:一个统一的 Any-to-Any 多模态理解与生成模型
随着多模态技术的不断发展,越来越多的模型被提出以解决跨文本与图像等多种数据类型的任务。Janus-1.3B 是由 DeepSeek 推出的一个革命性的模型,它通过解耦视觉编码并采用统一的 Transformer 架构,带来了一个高度灵活的 any-to-any 多模态框架…...

论文信息搜集
系列博客目录 文章目录 系列博客目录1.秩典型相关分析及其在视觉搜索重排序中的应用《Rank canonical correlation analysis and its application in visual search reranking》2.利用边信息的规范秩估计在多维谐波恢复中的应用《Canonical Rank Estimation Using Side Informa…...

实操给自助触摸一体机接入大模型语音交互
本文以CSK6 大模型开发板串口触摸屏为例,实操讲解触摸一体机怎样快速增加大模型语音交互功能,使用户能够通过语音在一体机上查询信息、获取智能回答及实现更多互动功能等。 在本文方案中通过CSK6大模型语音开发板采集用户语音,将语音数据传输…...

图表的放大和刷新功能
正常图表渲染显示: // 漏斗ading动画 let myChartone; // 获取配置项 let optionone; // 获取漏斗的数据 let order; let pay_order; let pay_order_num; let pay_order_num_num; let optiones; // 漏斗渲染 function polt(data) {// 从名为data的对象中获取ordata属…...

SQLServer利用QQ邮箱做SMTP服务器发邮件
环境 Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) SQL Server Management Studio 15.0.18384.0 SQL Server 管理对象 (SMO) 16.100.46367.54 Microsoft .NET Framework 4.0.30319.42000 操作系统 Windows Server2019 ———————————————— 前言…...

flutter 多文本,其中文本下划线往下移动
变态需求 flutter中再满足多行文本,文本内有多个样式,并且多个样式可触发事件的情况,将其中的一部分文本的下划线往下移 方式一: 实现 使用RichText组件,主要是看中里面的WidgetSpan可以穿child为一个widget 实现源…...

7.OPEN SQL
总学习目录请点击下面连接 SAP ABAP开发从0到入职,冷冬备战-CSDN博客 目录 编辑 1.OPEN-SQL 简单回顾 R3体系 OEPN-SQL 2.OPEN-SQL 读取数据 2.1Select 语句 select 1条数据 多条数据与into AS别名 2.2INTO 结构体 内表 例子 2.3FROM 选择动态表…...