吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3314|回复: 19
收起左侧

[系统底层] win32笔记十九 模块隐藏(完结)

  [复制链接]
huchen 发表于 2024-5-24 00:32
之前的索引

模块隐藏

断链

  1. TEB(Thread Environment Block),他记录的相关线程的信息,每一个线程都有自己的TEB,FS[0]即是当前线程的TEB

    代码:mov eax,fs:[0]

  2. PEB(Process Environment Block,进程环境块)存放进程信息,每个进程都有自己的PEB信息,TEB偏移0x30即当前进程的PEB

    代码:mov eax,fs:[0x30]

    ​          mov PEB,eax

  3. TEB与PEB都在用户空间

首先在windbg查看TEB

0: kd> dt  _TEB
ntdll!_TEB
+0x000 NtTib            : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId         : _CLIENT_ID
+0x028 ActiveRpcHandle  : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
+0x034 LastErrorValue   : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread  : Ptr32 Void
+0x040 Win32ThreadInfo  : Ptr32 Void
+0x044 User32Reserved   : [26] Uint4B
+0x0ac UserReserved     : [5] Uint4B
+0x0c0 WOW32Reserved    : Ptr32 Void
+0x0c4 CurrentLocale    : Uint4B
+0x0c8 FpSoftwareStatusRegister : Uint4B
+0x0cc SystemReserved1  : [54] Ptr32 Void
+0x1a4 ExceptionCode    : Int4B
+0x1a8 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
+0x1bc SpareBytes1      : [24] UChar
+0x1d4 GdiTebBatch      : _GDI_TEB_BATCH
+0x6b4 RealClientId     : _CLIENT_ID

只截取了部分,这里我们需要知道的是第一个和第三个

第一个是一个结构体,看看里面的详情

0: kd> dt  _NT_TIB
ntdll!_NT_TIB
+0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x004 StackBase        : Ptr32 Void
+0x008 StackLimit       : Ptr32 Void
+0x00c SubSystemTib     : Ptr32 Void
+0x010 FiberData        : Ptr32 Void
+0x010 Version          : Uint4B
+0x014 ArbitraryUserPointer : Ptr32 Void
+0x018 Self             : Ptr32 _NT_TIB

第一个成员是异常链表

第二第三个成员是线程的堆栈的顶和底,但我感觉第三个更像是范围

所以后面就以此类推,可以在OD里看到,随便拖进一个程序

输入命令就可以看到

image-20240522165313522.png

0: kd> dt  _CLIENT_ID
ntdll!_CLIENT_ID
+0x000 UniqueProcess    : Ptr32 Void
+0x004 UniqueThread     : Ptr32 Void

接下来就是进程ID和线程ID,可以看到为D94 = 3476(10)

image-20240522172125011.png

上面说的是TEB,那PEB在哪呢?

还是需要先找TEB,然后再偏移0x30的位置就是PEB,在OD找到后,右键,选择在数据窗口跟随

image-20240522174528252.png

这就是PEB的详情

结构可以在windbg里查看

0: kd> dt  _PEB
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged    : UChar
+0x003 SpareBool        : UChar
+0x004 Mutant           : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr              : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData    : Ptr32 Void
+0x018 ProcessHeap      : Ptr32 Void
+0x01c FastPebLock      : Ptr32 _RTL_CRITICAL_SECTION
+0x020 FastPebLockRoutine : Ptr32 Void
+0x024 FastPebUnlockRoutine : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
+0x02c KernelCallbackTable : Ptr32 Void
+0x030 SystemReserved   : [1] Uint4B
+0x034 AtlThunkSListPtr32 : Uint4B
+0x038 FreeList         : Ptr32 _PEB_FREE_BLOCK
+0x03c TlsExpansionCounter : Uint4B
+0x040 TlsBitmap        : Ptr32 Void
+0x044 TlsBitmapBits    : [2] Uint4B
+0x04c ReadOnlySharedMemoryBase : Ptr32 Void
+0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
+0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
+0x058 AnsiCodePageData : Ptr32 Void
+0x05c OemCodePageData  : Ptr32 Void
+0x060 UnicodeCaseTableData : Ptr32 Void

还是截取了部分,其它部分感兴趣的可自行查阅资料

当我们用API遍历进程有多少模块时,那这些API查的就是PEB里的Ldr成员,也就是偏移0xC

0: kd> dt  _PEB_LDR_DATA
ntdll!_PEB_LDR_DATA
+0x000 Length           : Uint4B
+0x004 Initialized      : UChar
+0x008 SsHandle         : Ptr32 Void
+0x00c InLoadOrderModuleList : _LIST_ENTRY
+0x014 InMemoryOrderModuleList : _LIST_ENTRY
+0x01c InInitializationOrderModuleList : _LIST_ENTRY
+0x024 EntryInProgress  : Ptr32 Void

在这个结构体里有三个很重要的双向链表

  • InLoadOrderModuleList 加载的模块序列
  • InMemoryOrderModuleList   在内存中的模块序列
  • InInitializationOrderModuleList   初始化中的模块序列

所以,当我们得知API是怎么查找到的模块,不就是从这儿找的吗,因此,只要我断了这个链,那不就找不到了吗,这就是所谓的模块隐藏方法之一

0: kd> dt  _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY     //代表按加载顺序构成的模块链表
+0x008 InMemoryOrderLinks : _LIST_ENTRY   //代表按内存顺序构成的模块链表
+0x010 InInitializationOrderLinks : _LIST_ENTRY   //代表按初始化顺序构成的模块链表
+0x018 DllBase          : Ptr32 Void      //该模块的基地址
+0x01c EntryPoint       : Ptr32 Void      //该模块的入口
+0x020 SizeOfImage      : Uint4B          //该模块的影像大小
+0x024 FullDllName      : _UNICODE_STRING     //包含路径的模块名
+0x02c BaseDllName      : _UNICODE_STRING     //不包含路径的模块名
+0x034 Flags            : Uint4B
+0x038 LoadCount        : Uint2B      //该模块的引用计数
+0x03a TlsIndex         : Uint2B
+0x03c HashLinks        : _LIST_ENTRY
+0x03c SectionPointer   : Ptr32 Void
+0x040 CheckSum         : Uint4B
+0x044 TimeDateStamp    : Uint4B
+0x044 LoadedImports    : Ptr32 Void
+0x048 EntryPointActivationContext : Ptr32 Void
+0x04c PatchInformation : Ptr32 Void

这就是链表中的结构,可看后面的注释

还是用刚刚的办法,来数据跟随一下这个结构体

在0xC的位置

image-20240522210104248.png

跟过去后,在下面就会看到模块名等,这里说一下这里是unicode编码

这也是一个结构体

0: kd> dt  _UNICODE_STRING
ntdll!_UNICODE_STRING
+0x000 Length           : Uint2B
+0x002 MaximumLength    : Uint2B
+0x004 Buffer           : Ptr32 Uint2B

所以这就是为什么在0xC0 + 0x28 = 0xE8,(原来是+0x24,不要搞混了)

接下来就是用代码来实现断链了,可能有人会问了,那断了,还能使用吗?是可以的,因为已经加载到了内存中,这些链表无非就是个备份的作用

代码

// 模块隐藏.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
}UNICODE_STRING,*PUNICODE_STRING;

typedef struct _PEB_LDR_DATA
{
   ULONG Length;
   BOOLEAN Initialized;
   PVOID SsHandle;
   LIST_ENTRY InLoadOrderModuleList;
   LIST_ENTRY InMemoryOrderModuleList;
   LIST_ENTRY InInitializationOrderModuleList;
   PVOID EntryInProgress;
}PEB_LDR_DATA,*PPEB_LDR_DATA;

typedef struct _LDR_DATA_TABLE_ENTRY
{

   LIST_ENTRY InLoadOrderModuleList;            //代表按加载顺序构成的模块链表
   LIST_ENTRY InMemoryOrderModuleList;          //代表按内存顺序构成的模块链表
   LIST_ENTRY InInitializationOrderModuleList;  //代表按初始化顺序构成的模块链表
   PVOID DllBase;                           //该模块的基地址
   PVOID EntryPoint;                        //该模块的入口
   ULONG SizeOfImage;                       //该模块的影像大小
   UNICODE_STRING FullDllName;              //包含路径的模块名
   UNICODE_STRING BaseDllName;              //不包含路径的模块名
   ULONG Flags;
   USHORT LoadCount;                        //该模块的引用计数
   USHORT TlsIndex; 
   LIST_ENTRY HashLinks;
   PVOID SectionPointer;
   ULONG CheckSum;
   ULONG TimeDateStamp;
}LDR_MODULE,*PLDR_MODULE;

void HideModule(char* ModuleName)
{
    HMODULE hMod = GetModuleHandle(ModuleName);
    PLIST_ENTRY Head,Cur;
    PPEB_LDR_DATA ldr;
    PLDR_MODULE ldm;
    __asm
    {
        mov eax,fs:[0x30]
        mov ecx,[eax+0xc]
        mov ldr,ecx
    }
    Head = &(ldr->InLoadOrderModuleList);
    Cur = Head->Flink;
    do
    {
        //宏 CONTAINING_RECORD 根据结构体中某一成员的地址来推算出该结构体整体的地址
        ldm = CONTAINING_RECORD(Cur,LDR_MODULE,InLoadOrderModuleList);

        if(hMod == ldm->DllBase)
        {
            //断加载链
            ldm->InLoadOrderModuleList.Blink->Flink = ldm->InLoadOrderModuleList.Flink;
            ldm->InLoadOrderModuleList.Flink->Blink = ldm->InLoadOrderModuleList.Blink;

            //断内存链
            ldm->InMemoryOrderModuleList.Blink->Flink = ldm->InMemoryOrderModuleList.Flink;
            ldm->InMemoryOrderModuleList.Flink->Blink = ldm->InMemoryOrderModuleList.Blink;

            //断初始化链
            ldm->InInitializationOrderModuleList.Blink->Flink = ldm->InInitializationOrderModuleList.Flink;
            ldm->InInitializationOrderModuleList.Flink->Blink = ldm->InInitializationOrderModuleList.Blink;
            break;

        }
        Cur = Cur->Flink;
    }while(Head != Cur);
}

int main(int argc, char* argv[])
{
    printf("************按任意键进行模块隐藏**************\n");
    getchar();
    HideModule("kernel32.dll");
    printf("************模块已成功隐藏**************\n");
    getchar();
    return 0;
}

这些代码相信都能看懂,只是按照我们的查找流程来的,所以上面定义了一些结构体,然后就是断链的操作,这些就是数据结构里的知识了,双向链表的删去一个元素的操作了,别忘了这里有三个,所以要删三次,无非就是跳过那删除的而已,代码不难,还请耐下心来揣摩

执行后,用其它调试软件来测试,发现只有DTdbg成功了,也就是海哥里用的调试器,OD、XDBG都不能隐藏,猜测这些调试器用了其它方法来获取模块的

这个代码也同样适用于VS2022,只是需要改一下API就可以了,库需要stdio.h和windows.h

VAD树

学习了断链来隐藏模块,那是不是就真的藏起来了?

真的藏起来了的话,那OD不就成功了吗,

所以断链只是在API的层面不提供查询模块的服务,还记得以前在windbg找程序吗?就是查虚拟内存使用情况的那个

用命令直接梭哈

image-20240522231039343.png

我在API层面隐藏了,但是在0环还是显露出来了,如果要实现在这里隐藏就要会写驱动

PE指纹

假如,我会写断链了,也会写驱动了,那是不是就真的隐藏了?

也不是,还有种方法,到OD里去,点击E可以看到有许多的模块,就拿第一个举例,是*.exe,在命令中输入db 模块地址(最左边的地址)

在数据窗口看

image-20240522232059676.png

仔细看我框住的地方,这些被称为PE指纹,只要看到这个,就可以认定这是个模块,其它的模块也一样,因为这些都是PE文件

所以,只要我利用这一特性,遍历内存,发现符合这个特征的就是一个模块

如果这三板斧你都实现了,但是还有LoadLibarary,我监控这个API呢?

即便你重写LoadLibrary,0环你总不能重写吧,那我在0环监控,你要加载dll总要是在操作系统里调用内核函数吧

所以,不管怎么隐藏,都是有痕迹的,所以要想人不知,除非己莫为,或者比你菜,比你菜的人就不会知道这些东西,因此有个信息差的因素在,导致能够隐藏模块

所以论隐藏的话,最好的方法就是无模块,我都没有,你怎么查啊

注入代码

在远程线程中,我们实现了在别人的进程里创建线程并执行了一段代码,也就是线程函数

有了这个基础,那我们来思考注入代码,那我把线程函数给复制到进程里,然后我还是按照原来的步骤创建远程线程,所以这就是注入代码的思路

听起来简单,实际要搞清楚两个问题

  1. 你要复制的函数是啥?
  2. 你复制过去的程序一定能正常执行吗?

首先来解决第一个问题

看一个非常简单的函数

// test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

int Fun(int x,int y)
{
    return x+y;
}

int main(int argc, char* argv[])
{
    Fun(1,2);
    return 0;
}

我们进汇编看一下

6:    int Fun(int x,int y)
7:    {
00401020 55                   push        ebp
00401021 8B EC                mov         ebp,esp
00401023 83 EC 40             sub         esp,40h
00401026 53                   push        ebx
00401027 56                   push        esi
00401028 57                   push        edi
00401029 8D 7D C0             lea         edi,[ebp-40h]
0040102C B9 10 00 00 00       mov         ecx,10h
00401031 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
00401036 F3 AB                rep stos    dword ptr [edi]

我们能看见这些汇编代码,那这些汇编是不是就存在与exe文件呢?

当然不是,实际存在的只是地址与汇编代码之间的机器码,我认为也可以叫硬编码,所以想把代码复制过去的,不是代码,而是机器码

这就是要复制过去的内容

接下来就是第二个问题,复制过去了就一定能执行吗?

那肯定不是,首先定义一个全局变量,在初始化,然后进汇编看看

8:        a = 1;
00401038 C7 05 34 7E 42 00 01 mov         dword ptr [a (00427e34)],1

可以看到他是把a的地址直接写进机器码里了,如果我复制进其它进程里,如果这个地址存了其它数据,或者根本就没有分配呢?

所以首先第一个条件就是:不许有全局变量

如果是常量字符串呢?一样的操作

8:        char* a = "huchen";
00401038 C7 45 FC 6C 2F 42 00 mov         dword ptr [ebp-4],offset string "huchen" (00422f6c)

可以看到还是一样的结果

所以第二个条件就是:不许有常量字符串

既然要远程线程线程,那肯定用到API吧,这总行了吧,一样自己写个看看汇编

8:        MessageBox(0,0,0,0);
00401038 8B F4                mov         esi,esp
0040103A 6A 00                push        0
0040103C 6A 00                push        0
0040103E 6A 00                push        0
00401040 6A 00                push        0
00401042 FF 15 AC A2 42 00    call        dword ptr [__imp__MessageBoxA@16 (0042a2ac)]
00401048 3B F4                cmp         esi,esp
0040104A E8 81 00 00 00       call        __chkesp (004010d0)

这里我以前说过,这是个间接调用,系统会预先留个位置,等到要用的时候会把系统函数的地址贴过来,所以在别的进程这个地址就不一定是系统调用的地址了

所以第三个条件就是:不许有系统调用

最后每一种就是函数嵌套,这个只是针对当前阶段来说,如果掌握了硬编码,这个就不是问题了

9:    int Fun(int x,int y)
10:   {
00401080 55                   push        ebp
00401081 8B EC                mov         ebp,esp
00401083 83 EC 40             sub         esp,40h
00401086 53                   push        ebx
00401087 56                   push        esi
00401088 57                   push        edi
00401089 8D 7D C0             lea         edi,[ebp-40h]
0040108C B9 10 00 00 00       mov         ecx,10h
00401091 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
00401096 F3 AB                rep stos    dword ptr [edi]
11:       Test();
00401098 E8 72 FF FF FF       call        @ILT+10(Test) (0040100f)

可以看到Test的地址确定了,复制的话,就会把地址复制过去

所以有四大条件:

  1. 不许有全局变量
  2. 不许有常量字符串
  3. 不许有系统调用
  4. 不许有函数嵌套

看到这儿,可能就疑惑了,都要满足,这代码还有用吗

接下就用代码来实现创建一个文件

// 注入代码.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

typedef struct 
{
    DWORD CreateFileAddr;
    LPCTSTR lpFileName;
    DWORD dwDesiredAccess;
    DWORD dwShareMode;
    LPSECURITY_ATTRIBUTES lpSecurityAttributes;
    DWORD dwCreationDisposition;
    DWORD dwFlagsAndAttributes;
    HANDLE hTemplateFile;       
}CreateFile_New;

typedef HANDLE (WINAPI * New_CreateFile)(
                                        LPCTSTR lpFileName,
                                        DWORD dwDesiredAccess,
                                        DWORD dwShareMode,
                                        LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                                        DWORD dwCreationDisposition,
                                        DWORD dwFlagsAndAttributes,
                                        HANDLE hTemplateFile);

//编写要复制到目标进程的函数
DWORD __stdcall CreateFileNew(LPVOID lparam)
{
    CreateFile_New* Ncreate = (CreateFile_New*)lparam;
    New_CreateFile lpCreateFile;

    lpCreateFile = (New_CreateFile)Ncreate->CreateFileAddr;
    lpCreateFile(
        Ncreate->lpFileName,
        Ncreate->dwDesiredAccess,
        Ncreate->dwShareMode,
        Ncreate->lpSecurityAttributes,
        Ncreate->dwCreationDisposition,
        Ncreate->dwFlagsAndAttributes,
        Ncreate->hTemplateFile);
    return 0;
}

BOOL CreateFileRemot(DWORD ProcId,char *FilePath)
{
    HANDLE hThread;
    DWORD ThreadFunSize;
    LPVOID lpFileName;
    LPVOID lpThreadFun;
    LPVOID lpFileParam;
    CreateFile_New NCreateFile;
    BOOL Ret;
    HANDLE hProc;
    HMODULE hModule;
    DWORD FunAddr;

    Ret = 0;
    hProc = 0;
    ThreadFunSize = 0x400;
    //1.获取进程的句柄
    hProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,ProcId);
    if(hProc == NULL)
    {
        OutputDebugString("获取失败\n");
        return FALSE;
    }

    //2.分配3段内存:存储参数、线程函数、文件名

    //2.1存储文件名
    lpFileName = VirtualAllocEx(hProc,NULL,strlen(FilePath),MEM_COMMIT,PAGE_READWRITE);

    //2.2存储线程函数
    lpThreadFun = VirtualAllocEx(hProc,NULL,ThreadFunSize,MEM_COMMIT,PAGE_READWRITE);

    //2.3存储参数
    lpFileParam = VirtualAllocEx(hProc,NULL,sizeof(CreateFile_New),MEM_COMMIT,PAGE_READWRITE);

    //3.初始化createfile函数
    NCreateFile.dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
    NCreateFile.dwShareMode = 0;
    NCreateFile.lpSecurityAttributes = NULL;
    NCreateFile.dwCreationDisposition = OPEN_ALWAYS;
    NCreateFile.dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
    NCreateFile.hTemplateFile = NULL;

    //4.获取createfile地址
    hModule = LoadLibrary("kernel32.dll");
    NCreateFile.CreateFileAddr = (DWORD)GetProcAddress(hModule,"CreateFileA");
    FreeLibrary(hModule);

    //5.初始化文件名
    NCreateFile.lpFileName = (LPCTSTR)lpFileName;

    //6.修正线程函数地址
    FunAddr = (DWORD)CreateFileNew;
    if(*(BYTE*)FunAddr == 0Xe9)
    {
        FunAddr = FunAddr + 5 + *(DWORD*)(FunAddr+1);
    }

    //7.开始复制

    //7.1拷贝文件名
    WriteProcessMemory(hProc,lpFileName,FilePath,strlen(FilePath)+1,0);
    //7.2拷贝线程函数
    WriteProcessMemory(hProc,lpThreadFun,(LPVOID)FunAddr,ThreadFunSize,0);
    //7.3拷贝参数
    WriteProcessMemory(hProc,lpFileParam,&NCreateFile,sizeof(CreateFile_New),0);

    //8.开始复制
    hThread = CreateRemoteThread(hProc,NULL,0,(LPTHREAD_START_ROUTINE)lpThreadFun,lpFileParam,0,NULL);
    if(hThread == NULL)
    {
        OutputDebugString("创建失败\n");
        CloseHandle(hProc);
        return FALSE;
    }

    //9.关闭资源
    //CloseHandle(hProc);
    //CloseHandle(hThread);

    return TRUE;

}

int main(int argc, char* argv[])
{
    CreateFileRemot(3380,"C:\\huchen.txt");
    return 0;
}

首先我定义了一个结构体,里面可以分为两部分,一个是CreateFile的地址,另一个部分是这个函数的参数,接下来就是定义新的CreateFile函数,也是我们要复制进进程的函数

然后就是编写一些准备工作

这里说一下2,要实现这个函数,还是在别的进程里实现,就需要在别的内存里有这些东西,所以是必须的

还有6,为啥还要加,继续看到Test代码

;main函数中
13:       Fun(1,2);
00401068 6A 02                push        2
0040106A 6A 01                push        1
0040106C E8 94 FF FF FF       call        @ILT+0(Fun) (00401005)

;jmp过渡
@ILT+0(?Fun@@YAHHH@Z):
00401005 E9 16 00 00 00       jmp         Fun (00401020)
@ILT+5(_main):
0040100A E9 41 00 00 00       jmp         main (00401050)

;Fun函数
6:    int Fun(int x,int y)
7:    {
00401020 55                   push        ebp
00401021 8B EC                mov         ebp,esp

在从main函数执行Fun函数时,中间会有个jmp,所以不能直接把地址给出去,需要加下工,你会发现规律要跳到Fun函数,在下一个地址加上E9后的一字节就是Fun函数的地址,所以需要那些操作

我把认为会产生疑惑的地方给解释了一下,相信其他的都能明白

执行后,就会在C盘生成huchen.txt

学了这个,建议在自行写其它的方式,来巩固一下,也正是检验自己是否真的掌握了

完结

至此,win32旅程结束了,虽然海哥说有,但是我这儿没有后面的课了

感谢各位大佬的耐心观看,小生的笔记如能帮助到各位,是小生的荣幸之至,虽然win32完结了,但是学习的脚步永远不能停,在此祝看到这儿的各位前程似锦

免费评分

参与人数 12威望 +1 吾爱币 +30 热心值 +10 收起 理由
zhangy1219 + 1 我很赞同!
asciibase64 + 1 谢谢@Thanks!
jhoneyr + 1 + 1 谢谢@Thanks!
che_shen + 1 已经处理,感谢您对吾爱破解论坛的支持!
willJ + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
x7032360 + 1 + 1 谢谢@Thanks!
allspark + 1 + 1 用心讨论,共获提升!
nonefree + 1 + 1 用心讨论,共获提升!
rookie12138 + 1 + 1 热心回复!
yunji + 1 用心讨论,共获提升!
wanfon + 1 + 1 热心回复!
Passerby + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

兔子哥哥 发表于 2024-5-24 09:14
其实不必手动加载,直接读了文件在进程展开修复一下就行了,取到所有地址过后,抹掉头尾就行了
ioyr5995 发表于 2024-5-24 05:39
Ke0n 发表于 2024-5-24 07:25
rlx2003 发表于 2024-5-24 08:28
大佬学习,我再旁边看大佬就很满足了,我不学习,太难
PastYiHJ 发表于 2024-5-24 08:51
顶,跟着大佬学习
tzblue 发表于 2024-5-24 09:50
请问楼主,有配套书吗?
AndroidStudy 发表于 2024-5-24 09:59
海哥反汇编引擎搞起来,内核搞起来
wzj1234567 发表于 2024-5-24 16:15

持续跟着大佬学习,一定能有进步!
稻海香 发表于 2024-5-24 16:53
后续还有其他的吗,期待你的大作。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 16:46

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表