当前位置: 首页 > news >正文

固定参数-以京东sign逆向为例

前言
在逆向过程中,需要结合frida或unidbg,对整个算法进行一步步的分析,有时候我们分析完某一部分,想要继续往下分析时,需要重新发起请求,这时候的参数往往都已经改变了,这样会打断我们的节奏,影响效率。此外,有些算法除了我们外部传进去的参数外,还有一些其他的参数参与了加密,比如时间戳,随机数,一旦这些参与了算法,那么即使每次的传入参数不变,加密的结果还是会变。

外部输入参数的固定
frida
在京东app的hook中,我们选择编写一个函数,能够固定的调用Java层的native函数。

var bptr = Module.findBaseAddress('libjdbitmapkit.so')
console.log(bptr);function hook_12ECC() {Interceptor.attach(bptr.add(0x12ECC+1), {onEnter: function(args) {this.arg0 = args[0];this.arg3 = args[3];console.log(args[0], args[1], args[2], args[3], args[4]);dump("arg0-ptr0", args[0].readPointer());dump("arg0-ptr1", args[0]);dump("arg0-ptr1", args[0].add(4).readPointer(), 64);console.log("arg1", args[1].readCString());// dump("arg2", args[2]);console.log("arg3", args[3].readCString(parseInt(args[4])));},onLeave: function(){console.log("arg0-ret", this.arg0);dump("ret-arg0-ptr1", this.arg0);// dump("ret-arg0-ptr2", this.arg0.add(8).readPointer());dump("12ecc-ret-arg2", this.arg3)}})
}function callBitmapkitUtils() {var BitmapkitUtils = Java.use('com.jingdong.common.utils.BitmapkitUtils');var currentApplication = Java.use("android.app.ActivityThread").currentApplication();var context = currentApplication.getApplicationContext();var b = 'clientImage';var c = '{"moduleParams":{"18":"1565611060638","19":"1565229712150","25":"1567478504636","27":"1602488415048","28":"1631069159956","30":"1567404005627","32":"1567997588476","34":"1593508185597","35":"1568708316462","37":"1630293538664","42":"1623741761542","44":"1569247647090","46":"1588839806224","47":"1571295610042","61":"1582091758495","70":"1585279774645","74":"1586781606615"}}';var d = 'd5a585639f505b18';var e = 'android';var f = '10.2.0';var res = BitmapkitUtils.getSignFromJni(context, b, c, d, e, f);console.log('res: ', res);
}Java.perform(function() {hook_12ECC();
})

然后启动frida之后,可以在shell中输入callBitmapkitUtils()来调用函数。

这样一来不像在手机上滑动页面、点击页面那样,有时会有多个请求发出,会多次调用加密的方法。这样的好处是,再也不用在手机上操作了,而且请求的内容和个数是可控的。不过我们注意到京东的参数里有st和sv这两个参数,这可不是由我们传入的,属于内部输入参数,接下来我们要固定它们。

unidbg
对于unidbg而言,在我们编写代码的时候,一般都是固定输入的

内部输入参数的固定
frida
对于内部输入参数而言,可能有时间戳,随机数,常量(数字或字符),其中前2个是会改变的,这会影响逆向分析,所以需要固定这两个参数。时间戳一般是调用libc.so的gettimeofday函数,随机数则是调用libc.so的lrand48或srand48

function hook_libc(){var ptr_t = Module.findExportByName("libc.so", "gettimeofday");Interceptor.attach(ptr_t, {onEnter: function(args){this.arg0 = args[0];},onLeave: function() {this.arg0.writeU32(1639393559);this.arg0.add(4).writeU32(0);}});Interceptor.attach(Module.findExportByName("libc.so" , "lrand48"), {onEnter: function(args) {},onLeave:function(retval){retval.replace(1);}});
}
Java.perform(function() {hook_libc();hook_12ECC();
})

这样一来,即使多次运行,st和sv也不会改变,有利于我们的分析。

不过,固定时间戳有个问题,其他函数在获取时间戳的时候发现不对,可能会导致frida环境崩溃,所以我们希望只在调用的时候固定时间戳。所以我们更新如下代码

var logvar = 0;function callBitmapkitUtils() {var BitmapkitUtils = Java.use('com.jingdong.common.utils.BitmapkitUtils');var currentApplication = Java.use("android.app.ActivityThread").currentApplication();var context = currentApplication.getApplicationContext();var b = 'clientImage';var c = '{"moduleParams":{"18":"1565611060638","19":"1565229712150","25":"1567478504636","27":"1602488415048","28":"1631069159956","30":"1567404005627","32":"1567997588476","34":"1593508185597","35":"1568708316462","37":"1630293538664","42":"1623741761542","44":"1569247647090","46":"1588839806224","47":"1571295610042","61":"1582091758495","70":"1585279774645","74":"1586781606615"}}';var d = 'd5a585639f505b18';var e = 'android';var f = '10.2.0';logvar = 1;var res = BitmapkitUtils.getSignFromJni(context, b, c, d, e, f);logvar = 0;console.log('res: ', res);
}function hook_libc(){var ptr_t = Module.findExportByName("libc.so", "gettimeofday");Interceptor.attach(ptr_t, {onEnter: function(args){this.arg0 = args[0];},onLeave: function() {if (logvar) {this.arg0.writeU32(1639393559);this.arg0.add(4).writeU32(0);}}});Interceptor.attach(Module.findExportByName("libc.so" , "lrand48"), {onEnter: function(args) {},onLeave:function(retval){if (logvar){retval.replace(1);}}});
}

这样一来,只有在logvar值为1时才会固定参数。而logvar的默认值为0,只有在调用callBitmapkitUtils方法的时候才会改为1,调用完成后又会改为0。

unidbg
对于unidbg,我们运行多次后会发现,时间戳st会变,sv一直是111,好像和frida上的表现不一样,难道出了什么问题?

其实如果研究了京东libjdbitmapkit.so就会发现sv的后两位都是随机数余3。

而在unidbg对libc.so的随机数生成的实现中,种子是固定的(我猜的,没深究源码),导致生成的随机数的顺序是固定的,继而导致余数是固定的。

public void hook_libc() {IHookZz hookZz = HookZz.getInstance(emulator);hookZz.wrap(module.findSymbolByName("lrand48"), new WrapCallback<HookZzArm32RegisterContext>() {@Overridepublic void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {}@Overridepublic void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {int old = ctx.getIntArg(0);System.out.println("Origin rand:" + old);ctx.setR0(1);}});hookZz.wrap(module.findSymbolByName("gettimeofday"), new WrapCallback<HookZzArm32RegisterContext>() {@Overridepublic void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {Pointer pointer = ctx.getR0Pointer();ctx.push(pointer);}@Overridepublic void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {Pointer pointer = ctx.pop();pointer.setLong(0, 1639388888);pointer.setLong(4, 0);}});
}
public static void main(String[] args) {JingDong test = new JingDong();test.hook_libc();test.callSign();
}

可以看到,时间戳已经被固定下来了,而打印出来的两个随机数,他们的除以3的余数都为1,这也说明了为什么固定参数之前sv的值一直是111。

unidbg完整代码
package com.jingdong;import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.hook.hookzz.*;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.linux.android.dvm.jni.ProxyDvmObject;
import com.github.unidbg.linux.android.dvm.wrapper.DvmInteger;
import com.github.unidbg.memory.Memory;
import com.sun.jna.Pointer;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.ParsingException;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.security.cert.X509Certificate;public class JingDong extends AbstractJni {private final AndroidEmulator emulator;private final VM vm;private final Module module;public static String pkgName = "com.jingdong.app.mall";public static String apkPath = "unidbg-android/src/test/java/com/jingdong/jingdong9.2.2.apk";public static String soPath = "unidbg-android/src/test/java/com/jingdong/libjdbitmapkit.so";private static final String APK_PATH = "/data/app/com.jingdong.app.mall.apk";JingDong() {emulator = AndroidEmulatorBuilder.for32Bit().setProcessName(pkgName).build();final Memory memory = emulator.getMemory();memory.setLibraryResolver(new AndroidResolver(23));vm = emulator.createDalvikVM(new File(apkPath));DalvikModule dm = vm.loadLibrary(new File(soPath), false);vm.setJni(this);vm.setVerbose(true);dm.callJNI_OnLoad(emulator);module = dm.getModule();}@Overridepublic DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {switch (signature) {case "com/jingdong/common/utils/BitmapkitUtils->a:Landroid/app/Application;": {return vm.resolveClass("android/app/Activity", vm.resolveClass("android/content/ContextWrapper", vm.resolveClass("android/content/Context"))).newObject(null);}}return super.getStaticObjectField(vm, dvmClass, signature);}@Overridepublic DvmObject<?> getObjectField(BaseVM vm, DvmObject<?> dvmObject, String signature) {switch (signature) {case "android/content/pm/ApplicationInfo->sourceDir:Ljava/lang/String;": {return new StringObject(vm, APK_PATH);}}return super.getObjectField(vm, dvmObject, signature);}@Overridepublic DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {switch (signature) {case "com/jingdong/common/utils/BitmapkitZip->unZip(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)[B": {StringObject apkPath = varArg.getObjectArg(0);StringObject directory = varArg.getObjectArg(1);StringObject filename = varArg.getObjectArg(2);if (APK_PATH.equals(apkPath.getValue()) &&"META-INF/".equals(directory.getValue()) &&".RSA".equals(filename.getValue())) {byte[] data = vm.unzip("META-INF/JINGDONG.RSA");return new ByteArray(vm, data);}}case "com/jingdong/common/utils/BitmapkitZip->objectToBytes(Ljava/lang/Object;)[B": {DvmObject<?> obj = varArg.getObjectArg(0);byte[] bytes = objectToBytes(obj.getValue());return new ByteArray(vm, bytes);}}return super.callStaticObjectMethod(vm ,dvmClass, signature, varArg);}@Overridepublic DvmObject<?> newObject(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {switch (signature) {case "sun/security/pkcs/PKCS7-><init>([B)V": {ByteArray array = varArg.getObjectArg(0);try {return vm.resolveClass("sun/security/pkcs/PKCS7").newObject(new PKCS7(array.getValue()));} catch (ParsingException e) {throw new IllegalStateException(e);}}}return super.newObject(vm, dvmClass, signature, varArg);}@Overridepublic DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {switch (signature) {case "sun/security/pkcs/PKCS7->getCertificates()[Ljava/security/cert/X509Certificate;": {PKCS7 pkcs7 = (PKCS7) dvmObject.getValue();X509Certificate[] certificates = pkcs7.getCertificates();return ProxyDvmObject.createObject(vm, certificates);}}return super.callObjectMethod(vm, dvmObject, signature, varArg);}@Overridepublic DvmObject<?> newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {switch (signature) {case "java/lang/StringBuffer-><init>()V": {return vm.resolveClass("java/lang/StringBuffer").newObject(new StringBuffer());}case "java/lang/Integer-><init>(I)V": {return DvmInteger.valueOf(vm, vaList.getIntArg(0));}}return super.newObjectV(vm, dvmClass, signature, vaList);}@Overridepublic DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {switch (signature) {case "java/lang/StringBuffer->append(Ljava/lang/String;)Ljava/lang/StringBuffer;": {StringBuffer buffer = (StringBuffer) dvmObject.getValue();StringObject str = vaList.getObjectArg(0);buffer.append(str.getValue());return dvmObject;}case "java/lang/Integer->toString()Ljava/lang/String;": {return new StringObject(vm, ((Integer)dvmObject.getValue()).toString());}case "java/lang/StringBuffer->toString()Ljava/lang/String;": {return new StringObject(vm, ((StringBuffer)dvmObject.getValue()).toString());}}return super.callObjectMethodV(vm, dvmObject, signature, vaList);}private static byte[] objectToBytes(Object obj) {try {ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(obj);oos.flush();byte[] array = baos.toByteArray();oos.close();baos.close();return array;} catch (IOException e) {throw new IllegalStateException(e);}}public void hook_libc() {IHookZz hookZz = HookZz.getInstance(emulator);hookZz.wrap(module.findSymbolByName("lrand48"), new WrapCallback<HookZzArm32RegisterContext>() {@Overridepublic void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {}@Overridepublic void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {int old = ctx.getIntArg(0);System.out.println("Origin rand:" + old);ctx.setR0(1);}});hookZz.wrap(module.findSymbolByName("gettimeofday"), new WrapCallback<HookZzArm32RegisterContext>() {@Overridepublic void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {Pointer pointer = ctx.getR0Pointer();ctx.push(pointer);}@Overridepublic void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {Pointer pointer = ctx.pop();pointer.setLong(0, 1639388888);pointer.setLong(4, 0);}});}public void callSign() {DvmClass cBitmapkitUtils = vm.resolveClass("com/jingdong/common/utils/BitmapkitUtils");StringObject ret = cBitmapkitUtils.callStaticJniMethodObject(emulator, "getSignFromJni()(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",vm.resolveClass("android/content/Context").newObject(null),"clientImage","{\"moduleParams\":{\"18\":\"1565611060638\",\"19\":\"1565229712150\",\"25\":\"1567478504636\",\"27\":\"1602488415048\",\"28\":\"1631069159956\",\"30\":\"1567404005627\",\"32\":\"1567997588476\",\"34\":\"1593508185597\",\"35\":\"1568708316462\",\"37\":\"1630293538664\",\"42\":\"1623741761542\",\"44\":\"1569247647090\",\"46\":\"1588839806224\",\"47\":\"1571295610042\",\"61\":\"1582091758495\",\"70\":\"1585279774645\",\"74\":\"1586781606615\"}}","d5a585639f505b18","android","10.2.0");System.out.println(ret.getValue());}public static void main(String[] args) {JingDong test = new JingDong();test.hook_libc();test.callSign();}
}

关于京东加密
其实京东app有3套加密方案,会根据随机数不同来选择不同的方案,而unidbg生成的随机数和京东cv的生成方案导致sv一直是固定的,从而一直调用其中一套方案。我们在逆向的时候,其实只需要逆向出其中一套方案即可,那个简单选哪个,如果刚好是调用的那套方案的话那还好。如果不是,一时之间又不知道怎么处理的话就有点倒霉了。
我将这个解密方法封装成api了,直接调用api可以解密,很方便了
技术交流QQ 408737515

相关文章:

固定参数-以京东sign逆向为例

前言 在逆向过程中&#xff0c;需要结合frida或unidbg&#xff0c;对整个算法进行一步步的分析&#xff0c;有时候我们分析完某一部分&#xff0c;想要继续往下分析时&#xff0c;需要重新发起请求&#xff0c;这时候的参数往往都已经改变了&#xff0c;这样会打断我们的节奏&a…...

在macOS 上执行sed命令报错问题

错误描述 在macOS 上执行sed命令&#xff0c;报错 sed -i s/book/books/g demo.txt sed: 1: extra characters at the end of d command解决方法 原因是mac的和linux写法不一样 linux sed -i s/book/books/g demo.txtmac sed -i s/book/books/g demo.txt...

ARP欺骗

ARP协议&#xff1a; 地址解析协议&#xff0c;将IP地址转换为对应的mac地址&#xff0c;属链路层协议 ip地址&#xff1a; ip地址本义是为互联网上的每一个网络和每一台主机配置一个唯一的逻辑地址&#xff0c;它的格式表示为&#xff1a;&#xff08;A.B.C.D&#xff09;。其…...

pip切换下载源(多种国内源)

pip切换下载源 一、pip二、使用步骤1.查看源2.切换源 一、pip pip 是一个现代的&#xff0c;通用的 Python 包管理工具 二、使用步骤 1.查看源 使用以下命令查看当前pip的下载源 pip config list2.切换源 在国内使用官方下载依赖往往速度慢&#xff0c;易出错&#xff0c…...

ARM Cortex-M 的 SP

文章目录 1、栈2、栈操作3、Cortex-M中的栈4、MDK中的SP操作流程5、Micro-Lib的SP差别1. 使用 Micro-Lib2. 未使用 Micro-Lib 在嵌入式开发中&#xff0c;堆栈是一个很基础&#xff0c;同时也是非常重要的名词&#xff0c;堆栈可分为堆 (Heap) 和栈 (Stack) 。 栈(Stack): 一种…...

【原创】鲲鹏ARM构架openEuler操作系统安装Oracle 19c

作者:einyboy 【原创】鲲鹏ARM构架openEuler操作系统安装Oracle 19c | 云非云计算机科学、自然科学技术科谱http://www.nclound.com/index.php/2023/09/03/%E3%80%90%E5%8E%9F%E5%88%9B%E3%80%91%E9%B2%B2%E9%B9%8Farm%E6%9E%84%E6%9E%B6openeuler%E6%93%8D%E4%BD%9C%E7%B3%BB%…...

k8s之存储篇---数据卷-挂载

挂载是指将定义在 Pod 中的数据卷关联到容器&#xff0c;同一个 Pod 中的同一个数据卷可以被挂载到该 Pod 中的多个容器上。 数据卷内子路径 有时候我们需要在同一个 Pod 的不同容器间共享数据卷。使用 volumeMounts.subPath 属性&#xff0c;可以使容器在挂载数据卷时指向数…...

无涯教程-JavaScript - TDIST函数

The TDIST function replaces the T.DIST.2T & T.DIST.RT functions in Excel 2010. 描述 该函数返回学生t分布的百分点(概率)​​,其中数值(x)是t的计算值,将为其计算百分点。 t分布用于小样本数据集的假设检验。使用此函数代替t分布的临界值表。 语法 TDIST(x,deg_fr…...

IP子网的划分

文章目录 一、子网掩码1. 产生背景2. 定义3. 分类 二、VLSM算法1. 得出下列参数2. 计算划分结果3. 举例子计算 三、常见子网划分对应关系四、练习IP编址题目需求解题1. 192.168.1.100/282. 172.16.0.58/263. 25.83.149.222/254. 100.100.243.18/205. 10.100.100.100/10 首先可以…...

弹性盒子的使用

一、定义 弹性盒子是一种用于按照布局元素的一维布局方法&#xff0c;它可以简便、完整、响应式地实现各种页面布局。 容器中存在两条轴&#xff0c;主轴和交叉轴(相当于我们坐标轴的x轴和y轴)。我们可以通过flex-direction来决定主轴的方向。 主轴&#xff08;main axis&am…...

软件测试/测试开发丨Selenium 网页frame与多窗口处理

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27048 一、多窗口处理. 1.1、多窗口简介 点击某些链接&#xff0c;会重新打开⼀个窗⼜&#xff0c;对于这种情况&#xff0c;想在新页⾯上操作&#xff0…...

MySQL高阶语句(三)

一、NULL值 在 SQL 语句使用过程中&#xff0c;经常会碰到 NULL 这几个字符。通常使用 NULL 来表示缺失 的值&#xff0c;也就是在表中该字段是没有值的。如果在创建表时&#xff0c;限制某些字段不为空&#xff0c;则可以使用 NOT NULL 关键字&#xff0c;不使用则默认可以为空…...

链表OJ练习(2)

一、分割链表 题目介绍&#xff1a; 思路&#xff1a;创建两个链表&#xff0c;ghead尾插大于x的节点&#xff0c;lhead尾插小于x的节点。先遍历链表。最后将ghead尾插到lhead后面&#xff0c;将大小链表链接。 我们需要在创建两个链表指针&#xff0c;指向两个链表的头节点&…...

ssh常用操作

ssh常用操作 SSH是一种安全协议&#xff0c;ssh是该协议的客户端程序&#xff0c;openssh-server则是该协议的服务端程序 常用系统都自带了ssh客户端程序&#xff0c;服务端程序则可能要安装 密码远程登陆 前提&#xff1a;服务器安装了openssh-server&#xff0c;未安装时…...

从AD迁移至AAD,看体外诊断领军企业如何用网络准入方案提升内网安全基线

摘要&#xff1a; 某医用电子跨国集团中国分支机构在由AD向AzureAD Global迁移时&#xff0c;创新使用宁盾网络准入&#xff0c;串联起上海、北京、无锡等国内多个职场与海外总部,实现平滑、稳定、全程无感知的无密码认证入网体验&#xff0c;并通过合规基线检查&#xff0c;确…...

Flutter系列文章-Flutter在实际业务中的应用

不同场景下的解决方案 1. 跨平台开发&#xff1a; 在移动应用开发中&#xff0c;面对不同的平台&#xff08;iOS和Android&#xff09;&#xff0c;我们通常需要编写两套不同的代码。而Flutter通过一套代码可以构建适用于多个平台的应用&#xff0c;大大提高了开发效率&#x…...

FPGA | Verilog仿真VHDL文件

当VHDL模块中有Generic块时&#xff0c;应该怎么例化&#xff1f; VHDL模块代码 entity GenericExample isgeneric (DATA_WIDTH : positive : 8; -- 泛型参数&#xff1a;数据宽度ENABLE_FEATURE : boolean : true -- 泛型参数&#xff1a;是否启用特定功能);Port ( clk : …...

微服务--Gatway:网关

routes: - id:order_route(路由唯一 标识&#xff0c;路由到order) uri&#xff1a;http://localhost:8020 #需要转发的地址 #断言规则&#xff08;用于路由规则的匹配&#xff09; predicates: -path/order-serv/** -pathlb://order-service # lb: 使用nacos中的本地…...

Django传递dataframe对象到前端网页

在django前端页面上展示的数据&#xff0c;还是使用django模板自带的语法 方式1 不推荐使用 直接使用 【df.to_html(indexFalse)】 使用to_html他会生成一个最基本的表格没有任何的样式&#xff0c;一点都不好看&#xff0c;如果有需要的话可以自行修改表格的样式&#xff0c;…...

iOS swift5 弹出提示文字(停留1~2s)XHToastSwift

CoderZhuXH/XHToastSwift - github // // XHToast.swift // XHToastSwiftExample // // Created by xiaohui on 16/8/12. // Copyright © 2016年 CoderZhuXH. All rights reserved. // 代码地址:https://github.com/CoderZhuXH/XHToastSwiftimport UIKit/*** Toast…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...

[特殊字符] 手撸 Redis 互斥锁那些坑

&#x1f4d6; 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作&#xff0c;想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁&#xff0c;也顺便跟 Redisson 的 RLock 机制对比了下&#xff0c;记录一波&#xff0c;别踩我踩过…...