在Ring3上实现文件碎甲(解锁)功能

GD32F470实战:如何用EXMC+SDRAM为LVGL打造超大内存池(附完整配置代码) 本文详细介绍了如何利用GD32F470的EXMC接口与SDRAM深度整合,为LVGL构建高性能内存解决方案。通过硬件架构设计、EXMC接口配置、高级内存管理策略及LVGL性能优化技巧,开发者可以突破微控制器内存限制,实现高分辨率显示和复杂动画效果。附完整配置代码,助力嵌入式GUI开发。 阅读详情
作者:cbns888
电邮:cbns888@163.com
一.概述:
如果一个病毒文件被植入正在运行的进程中,我们想要清除它时系统总会提供无法删除;有时编辑文件的进程被意外中止而文件句柄没有正确释放,导致此文件无法进行改写操作。现在我们会使用Unlocker之类的小工具去解锁,但在编写程序的可能会需要把这些功能包含在自己的代码中,本文就是自己写代码实现”如何关闭已经被加载的DLL或是正在使用的文件”功能,使用文章中的方法能很方便的完成文件解锁功能。
按最初的想法准备在ring0中完成这些功能,但在查找资料的过程中发现既然我们能在ring3中做,为什么不让这些方法更通用一些呢。其实功能实现并不难,主要是前期从哪里入手比较麻烦。
我们知道无论是动态库或是文件在加载到进程中时,总会有一个指向它的指针,如果让进程释放这段指针,那么这些文件就不会被系统锁定。下面将是我们的需要实现文件解锁功能而分解出的步骤
1.    枚举当前系统所有进程;
2.    查找进程中打开的文件句柄和加载的动态库句柄;
3.    通知进程关闭这些句柄。
二.详细设计
2.1查找进程加模的动态库模块
Let’s go,我们来分步完成它吧。对于枚举当前系统所有进程,在这里就不给出代码了,相信实现的方法很多。下面的代码段完成查找指定进程加载动库信息的功能(在这里使用了Jeffrey在《Windows核心编程》一书中提供的CToolhelp类,用它可以完成进程加载信息的分析功能,感谢Jeffrey,我一直在使用它)

// 自定义结构,保存打开句柄的的信息
typedef struct _UNFILE_INFO    {
    int nFileType;
    DWORD dwHandle;
    char *strFileName;
} UNFILE_INFO, *PUNFILE_INFO;
//////////////////////////////////////////////////////////////////////////
// 通过PID号取得PID打开的文件句柄信息
//////////////////////////////////////////////////////////////////////////
void
GetModules(DWORD dwProcessID, CList<PUNFILE_INFO, PUNFILE_INFO> &plsUnFileInfo)
{
    CToolhelp::EnableDebugPrivilege(TRUE);
    CToolhelp th(TH32CS_SNAPALL, dwProcessID);
    // 显示进程的详细资料
    MODULEENTRY32 me = { sizeof(me) };
    BOOL fOk = th.ModuleFirst(&me);
    for (; fOk; fOk = th.ModuleNext(&me))
    {
        PVOID pvPreferredBaseAddr = NULL;
        pvPreferredBaseAddr =GetModulePreferredBaseAddr(dwProcessID, me.modBaseAddr);
        // 取得进程模块信息
        PUNFILE_INFO pUnFileInfo = new UNFILE_INFO;
        // 模块地址
        pUnFileInfo->dwHandle = (DWORD)me.modBaseAddr;
        // 模块类型
        pUnFileInfo->nFileType = UNTYPE_DLL;
        // 模块名称
        pUnFileInfo->strFileName = new char[strlen(me.szExePath)+1];
        memset( pUnFileInfo->strFileName, 0, strlen(me.szExePath)+1);
        strcpy( pUnFileInfo->strFileName, me.szExePath);
        // 保存打开的模块信息
        plsUnFileInfo.AddTail( pUnFileInfo);
    }
}

上面功能完成了枚举进程加载的模块功能,我们把得到的枚举信息加入了链表中,以备后面使用。
2.2枚举进程打开的文件信息
下面将分段说明如何枚举指定进程打开的文件句柄。在这里我们需要使用两个DDK中提供的函数:
NTSTATUS
ZwQuerySystemInformation(
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
    OUT PVOID SystemInformation,
    IN ULONG SystemInformationLength,
    OUT PULONG ReturnLength OPTIONAL
);
NTSTATUS
  ZwQueryInformationFile(
    IN HANDLE  FileHandle,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    OUT PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
);
ZwQuerySystemInformation是个未公开函数,通过它的SYSTEM_INFORMATION_CLASS结构,我们能完成许多进程和线程的操作,下面是它的部分内容,在这时我们使用它的SystemHandleInformation(0x10),来完成文件句柄的操作。
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation,                 // 0
    SystemProcessorInformation,             // 1
    SystemPerformanceInformation,             // 2
…
    SystemHandleInformation,                 // 16
…
    SystemSessionProcessesInformation        // 53
} SYSTEM_INFORMATION_CLASS;
ZwQueryInformationFile可以根据参数FileInformationClass的不同值来返回不同的类型,在这里我们使用FileInformationClass=FileInformationClass来得到FILE_NAME_INFORMATION,从而得到文件句柄指向的文件名,下面是它的结构定义。
typedef struct _FILE_NAME_INFORMATION {
  ULONG  FileNameLength;
  WCHAR  FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;

因为需要在Ring3上使用DDK提供的函数,我们需要导出这些两个函数,下面是导出函数的示例代码:
{
    g_hNtDLL = LoadLibrary( "ntdll.dll" );
    if ( !g_hNtDLL )
    {
        return FALSE;
    }

    ZwQuerySystemInformation =
    (ZWQUERYSYSTEMINFORMATION)GetProcAddress( g_hNtDLL, "ZwQuerySystemInformation");
    if( ZwQuerySystemInformation == NULL)
    {
        return FALSE;
    }

    ZwQueryInformationFile =
    (ZWQUERYINFORMATIONFILE)GetProcAddress( g_hNtDLL, "ZwQueryInformationFile");
    if( ZwQueryInformationFile == NULL)
    {
        return FALSE;
    }
}
我们先来使用ZwQuerySystemInformation函数枚举系统中打开的所有文件的句柄,枚举出的信息将包含如下结构:
typedef struct _SYSTEM_HANDLE_INFORMATION {
    ULONG  ProcessId;
    UCHAR  ObjectTypeNumber;
    UCHAR  Flags;
    USHORT  Handle;
    PVOID  Object;
    ACCESS_MASK  GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
ObjectTypeNumber定义了句柄所属对像的类型,文件的ObjectType对不同的操作系统是不同的,所以需要先找到当前操作系统所定义的ObjectType值,这样才能在枚举出的众多句柄信息中找到哪些是文件句柄信息。通用的方法是我们CreateFile打开空设备NUL,记下它的句柄,用来比较。
UCHAR GetFileHandleType()
{
  HANDLE                     hFile;
  PSYSTEM_HANDLE_INFORMATION Info;
  ULONG                      r;
  UCHAR                      Result = 0;

  hFile = CreateFile("NUL", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);

  if (hFile != INVALID_HANDLE_VALUE)
  {
    Info = GetInfoTable(SystemHandleInformation);

    if (Info)
    {
      for (r = 0; r < Info->uCount; r++)
      {
        if (Info->aSH[r].Handle == (USHORT)hFile &&
                                    Info->aSH[r].uIdProcess == GetCurrentProcessId())
        {
          Result = Info->aSH[r].ObjectType;
          break;
        }
      }
      HeapFree(hHeap, 0, Info);
    }
    CloseHandle(hFile);
  }
  return Result;
}
现在知道了句柄的类型就可以枚举系统中打开的文件了。首先用句柄获取打开的文件名:
typedef struct _NM_INFO
{
  HANDLE  hFile;
  FILE_NAME_INFORMATION Info;
  WCHAR Name[MAX_PATH];
} NM_INFO, *PNM_INFO;

// 因为在在线程中取得文件名
DWORD WINAPI
  GetFileNameThread(PVOID lpParameter)

{
  PNM_INFO        NmInfo = lpParameter;
  IO_STATUS_BLOCK IoStatus;
  int r;

  NtQueryInformationFile(NmInfo->hFile, &IoStatus, &NmInfo->Info,
                       sizeof(NM_INFO) - sizeof(HANDLE), FileNameInformation);

  return 0;
}

void CFileProcess::GetFileName(HANDLE hFile, PCHAR TheName)
{

    HANDLE   hThread;
    PNM_INFO Info = new NM_INFO;
    char namebuf[2000] = {0};
    Info->Info = (PFILE_NAME_INFORMATION)namebuf;

    Info->hFile = hFile;
    Info->nRet = 0x00;
    
    // 在对打开的句柄调用ZwQueryInformationFile时,调用线程会等待PIPE中的消息
    // 如果PIPE中没有消息时,线程可能会永久挂起,所以使用一个等待超时来打开句柄
    hThread = CreateThread(NULL, 0, GetFileNameThread, Info, 0, NULL);
    if (WaitForSingleObject(hThread, 100) == WAIT_TIMEOUT)
        TerminateThread(hThread, 0);
    CloseHandle(hThread);
    // 调用句柄失败
    if( Info->nRet == 0x00)
    {
        delete Info;
        return ;
    }
    
    // 加上盘符
    wchar_t volume = GetVolumeName(hFile);
    if (volume != L'!')
    {
        wchar_t outstr[1000] = L"A:";
        outstr[0] = volume;
        memcpy(&outstr[2], Info->Info->FileName, Info->Info->FileNameLength);
        outstr[2+Info->Info->FileNameLength] = 0;
        WideCharToMultiByte(CP_ACP, 0, outstr, 2+Info->Info->FileNameLength, TheName, MAX_PATH, NULL, NULL);
    }
    delete Info;
    return ;
}

下面代码片段用来枚举打开的文件:
{
    // 取得操作系统文件句柄定义类型
    UCHAR ObFileType = GetFileHandleType();
    // 取得系统中打开的文件句柄列表
    PULONG buf = GetHandleList();
    if (buf == NULL)
        return ;
    Info = (PSYSTEM_HANDLE_INFORMATION)&buf[1];
    if (Info)
    {
        for (r = 0; r < buf[0]; r++, Info++)
        {
            if (Info->ObjectTypeNumber == ObFileType && Info->ProcessId == dwProcessID)
            {
                hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, Info->ProcessId);

                if (hProcess)
                {
                    // 复制句柄到当前进程中,这样方便对当前进程句柄取出文件名
                    // 因为共享一个FileObject,这两个文件句柄对像将由两个进程共享
                    if ( DuplicateHandle( hProcess, (HANDLE)Info->Handle,
                    GetCurrentProcess(), &hFile, 0, FALSE, DUPLICATE_SAME_ACCESS))
                    {
                        GetFileName(hFile, Name);
                        // 取得文件信息到链表中
                        if( strlen( Name)>0)
                        {
                            AfxTrace("PID=%d FileHandle %d FileName=%s", Info->ProcessId, Info->Handle, Name);
                            // 在这里加入你要保存的文件句柄信息
                        }

                        CloseHandle(hFile);
                    }
                    CloseHandle(hProcess);
                }
            }
        }
    }
}
2.3使用远线程方法关闭进程加载的模块和打开的文件
通过枚举进程加载的模块信息和打开的文件信息,我们已经得到系统中加载的DLL和文件名信息,以下是我们在链表中保存的信息:
{
DWORD    ProcessID    // 进程PID
BYTE    nHandleType    // 句柄类型是文件还是加载的DLL
Char strFileName[MAX_PATH]    // 文件名
}
如果我们需要关闭正在打开的文件,只需要在这个链表中以文件名进行查找,即得到打开文件的进程PID。怎么才能通知别的进程关闭相应的句柄呢,我们通过跨进程去关闭句柄是很困难的,不如直接注入代码到需要的进程中,然后直接关闭句柄就行了。
需要再遍写一个DLL用来注入到进程中通知进程关闭文件句柄。这个DLL不需要做别的处理,只需要在加载的地方根据不同的句柄类型使用不同的方法进行关闭即可。下面是注入到进程的DLL执行的关闭句柄函数:
Void CloseHandel( PVOID pHandle, BYTE nHandleType)
{
    If(HandleType = HANDLE_FILE)
FreeLibrary((HMODULE)pHandle);
    else
        CloseHandle((HANDLE)pHandle);
}
在DllMain中调用关闭句柄的函数:
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
    // Remove this if you use lpReserved
    UNREFERENCED_PARAMETER(lpReserved);

    if (dwReason == DLL_PROCESS_ATTACH)
    {
        DWORD nHandle=0;
        BYTE nType=0;
        TRACE0("MOPER.DLL Initializing!/n");
        AfxMessageBox("MOPER.DLL Initializing!");
        // 从碎甲程序所生成的文件句柄映射文件中取出要关闭的句柄信息
        // 方法很多我在这里直接用共享文件实现的,就不写出代码了
        GetHandle( nHandle, nType)
        // 关闭句柄            
        CloseHandel((PVOID)nHandle, nType);
...
    }
...
}
下面示例取出通过文件句柄链表中的PID,使用远程注入的方法向进程注入关闭句柄的DLL
{
    HANDLE hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | //允许远程创建线程
            PROCESS_VM_OPERATION | //允许远程VM操作
            PROCESS_VM_WRITE,//允许远程VM写
            FALSE, dwProcessId);
    if( hRemoteProcess == NULL)
        return FALSE;

    PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");
    int nLen = (strlen( pszLibFile)+1)*sizeof(char);
    char * pszLibFileRemote = (char *) VirtualAllocEx( hRemoteProcess, NULL, nLen, MEM_COMMIT, PAGE_READWRITE);
    if( pszLibFileRemote != NULL &&
        pfnStartAddr !=NULL)
    {
        if( WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (PVOID) pszLibFile, nLen, NULL))
        {
            HANDLE hThread = CreateRemoteThread( hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL);
            if( !hThread)
            {
                WaitForSingleObject(hThread, INFINITE);
                bRet = TRUE;
                CloseHandle(hThread);
            }
        }
        VirtualFreeEx(hRemoteProcess, pszLibFileRemote, 0, MEM_RELEASE);
    }
    CloseHandle( hRemoteProcess);
}
三.备注
对查找文件句柄的方法,参考了鄙人拙译( http://greatdong.blog.edu.cn)的“如何操作被占用文件”在此表示感谢。
使用了Jeffrey在《Windows核心编程》一书中提供的CToolhelp类,用它可以完成进程加载信息的分析功能,感谢Jeffrey 
Win10安全模式下修改C盘权限的完整指南(附解决开始菜单失灵方案) 本文提供了一份在Win10安全模式下修复因C盘权限误改导致开始菜单失灵的完整指南。文章深入剖析了权限体系,特别是TrustedInstaller角色的重要性,并详细讲解了通过安全模式进入系统、使用ICACLS命令或图形界面精准重置C盘关键目录权限的步骤,最终恢复系统核心功能。 阅读详情

相关推荐

抖音风控参数‘bd-ticket-guard-client-data’深度解析:从X.509证书到请求签名的完整链路

本文深度解析抖音风控参数‘bd-ticket-guard-client-data’的技术实现,从X.509证书体系到请求签名的完整安全链路。通过Python代码示例,揭示证书生成、签名算法及票据封装等核心机制,帮助开发者理解现代平台风控系统的多层防御架构设计。

weixin_42525738的博客 432

所有进程的名字和他使用的模块名以及其它信息

#include #include #include #include #include #include using namespace std; PVOID GetModulBaseAddr(DWORD dwProcessID,PVOID pvModuleRemote) { PVOID pvBaseAddr = NULL; IMAGE_DOS_HEADER dosH

g710710的专栏 1457

股票分时数据获取-东方财富

获取下股票分时数据,分时均价下线,分时成交额等,用于量化t0交易条件还是很不错了的。

meiaoxue1234的博客 1万+

Ring3下无驱动移除winlogon.exe进程ctrl+alt+del,win+u,win+l三个系统热键,非屏蔽热键

随手而作,纯粹技术研究,没什么实际意义。打开xuetr,正常情况下.winlogon.exe注册了三个热键。ctrl+alt+del,win+u,win+l三个。这三个键用SetWindowsHookEx()函数,使用键盘钩子也屏蔽不了。我们先把UnregisterSystemH

zwfgdlc的专栏 5962

5分钟搞定三网话费余额查询:手把手教你用PHP+HTML搭建查询系统(含API调用避坑指南)

本文详细介绍了如何使用PHP+HTML快速搭建三网话费余额查询系统,涵盖API调用避坑指南、前端UI设计及性能优化。通过统一处理移动、电信、联通三大运营商接口差异,实现高可用查询功能,并提供安全防护与生产部署建议,帮助开发者高效构建稳定可靠的话费查询工具。

weixin_29016833的博客 259

Altair HyperWorks软件二次开发:二次开发成果展示与报告撰写

HyperMesh Python API允许用户通过Python脚本控制HyperMesh的大部分功能,包括模型创建、修改和分析。它提供了丰富的函数库,可以处理节点、元素、材料属性、载荷和边界条件等。二次开发可以用于创建自定义工具,这些工具可以集成到HyperWorks中,提供特定的功能或简化复杂的操作。

kkchenjj的博客 1639

Ring3无敌进程让你的进程变得和smss.exe一样支持64

本帖最后由 奋斗丶小Z 于 2016-6-6 13:39 编辑 此函数可以启用或关闭开启之后变得和系统进程一样被杀系统直接蓝屏系统进程也是此函数实现的上图 可以用于进程保护 <ignore_js_op> %3MWID[XWF21C%4XP(FDCZI.jpg (98.99 KB, 下载次数: 0) 下载附件 保存到相册 ...

181

保姆级教程:ABAP 通过 HTTP POST 调用 OData 服务创建业务数据的具体例子

笔者之前的文章发布之后,有朋友在评论区留言,询问 ABAP 除了 Web Service 之外,是否也支持 HTTP 呢?ABAP 这么强大的语言,支持 HTTP 当然不在话下。网上有很多在 ABAP 系统基于 CL_HTTP_CLIENT 工具类,通过 HTTP 协议和第三方系统交互的代码例子。本文介绍笔者项目中一个实际例子,实现的是在 ABAP 系统 A 通过 HTTP 调用 OData 服务,在 ABAP 系统 B 创建业务数据的需求。下面我们按照这个套路来一步步实现。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 700

ring0和ring3的区别

 现在探讨内核程序和应用程序之间的本质区别。除了能用WDK编写内核程序和阅读一部分Windows的内核代码之外,我们还需要了解它们的本质是什么,它们和我们熟悉的应用程序有什么区别。      Intel的x86处理器是通过Ring级别来进行访问控制的,级别共分4层,从Ring0到Ring3(后面简称R0、R1、R2、R3)。R0层拥有最高的权限,R3层拥有最低的权限。按照Intel原有的构想,应...

爱码农爱生活 680

一篇文章认识《双目立体视觉》

双目立体视觉,由两个摄像头组成,像人的眼睛能看到三维的物体,具有深度的信息;单目视觉只能看到二维的物体。 1)双目摄像头 2)双目相机基线 3)打开双目摄像头 4)双目测距 视差disparity、 极线约束、 极线校正/立体校正、 a.双目标定 b.双目矫正 c.立体匹配 d.双目测距(三角测量) e.测距效果 立体视觉方法评测网站

黎国溥 7958

Hugging Face快速入门(重点讲解模型(Transformers)和数据集部分(Datasets))

1. Hugging Face是什么,提供了哪些内容 2. Hugging Face模型的使用(Transformer类库) 3. Hugging Face数据集的使用(Datasets类库)

iioSnail的博客 8万+

在Ring3上实现文件碎甲(解锁)功能--转载

在Ring3上实现文件碎甲(解锁)功能创建时间:2007-08-02文章提交:cbns888 (cbns888_at_163.com)作者:cbns888电邮:cbns888@163.com一.概述:如果一个病毒文件被植入正在运行的进程中,我们想要清除它时系统总会提供无法删除;有时编辑文件的进程被意外中止而文件句柄没有正确释放,导致此文件无法进行改写操作。现在我们会使用Unlocker之类的小

cuiyafang212的专栏 789

安装Openclaw[本地自动化AI助手]至windows【WSL2模式】系统 Openclaw for Windows

摘要:OpenClaw最佳兼容OpenAI系列模型,推荐使用ChatGPT API(需Auth鉴权),避免K*mi等模型导致的信用卡风险。Windows系统需满足WSL2支持条件(Win11或Win10 1903+版本)。安装需导入自签名根证书或跳过浏览器安全警告,通过离线包部署WSL发行版。使用时通过clawtoken命令获取网关认证令牌,并在浏览器完成设备配对。提供代购ChatGPT Plus账号服务(¥140/月),详细操作指南需加微信群获取文件。(150字)

qq_27246521的博客 456

VB Ring3下解锁文件的模块(二)

VB Ring3下解锁文件的模块(一) 优快云地址是:http://topic.youkuaiyun.com/u/20070925/11/c0fa3831-e732-46f2-81e3-2465d0577151.html?1416895339VB Ring3下解锁文件的模块(一) 博客地址:http://blog.youkuaiyun.com/chenhui530/archive/2007/10/03/181030

chenhui530的专栏 3422

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Elden Ring FPS解锁器及更多功能介绍

《Elden Ring FPS解锁器及更多功能》是一款专为《Elden Ring》游戏设计的实用工具,由资深开发者使用C#编写。该工具旨在移除游戏帧率限制、调整视野(FOV)、增加宽屏支持以及进行多种游戏修改。其核心优势在于,该工具通过内存补丁方式运行,不会修改任何游戏文件,确保了游戏的完整性和安全性。此外,它兼容所有游戏版本,包括合法的Steam版本和非官方版本,并且预计在未来更新中仍能保持兼容...

gitblog_00829的博客 896

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

ring0解锁文件

背景 当我们要删除一个文件的的时候,有时候会出现“文件被占用”或是“无法删除”的提示框,这往往是由于该文件句柄已经在其它进程中打开未关闭的缘故。 本文要介绍的是关闭在其它进程中的文件句柄,对文件进行解锁。现在,我把实现过程和原理,整理成文档,分享给大家。 实现原理 要实现对指定文件进行解锁,我们首先要做的就是获取这个文件所有被打开的文件句柄,然后在关闭这些句柄即可。那么接下来,我就对指定文件句柄的遍历以及结束文件句柄的实现原理分别进行解析。 遍历指定文件句柄 首先,我们使用 16 号功能调用 ZwQuery

LYSM 711

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

VB Ring3下解锁文件的模块

这篇文章参考了这个地址http://www.xfocus.net/articles/200708/935.html Attribute   VB_Name   =   "modLockFileInfo" Option   Explicit Private   Declare   Function   NtQueryInformationProcess   Lib   "NTDLL.DLL"  

chenhui530的专栏 5171
上一篇: 又见感染驱动文件和驱动文件感染新思路
下一篇: 恶意代码检测技术的演化
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值