首页
社区
课程
招聘
[原创]四种获取目标进程导入DLL模块地址的方法
2023-12-14 01:06 7317

[原创]四种获取目标进程导入DLL模块地址的方法

2023-12-14 01:06
7317

四种获取目标进程导入DLL模块地址的方法

本人在校大学生一枚,技术不太行,各位师傅将就看看。

1. 获取进程快照

tlhelp32.h头文件中,提供了CreateToolhelp32SnapshotAPI,可以获取获取指定进程以及这些进程使用的堆、模块和线程的快照。

1
2
3
4
HANDLE CreateToolhelp32Snapshot(
  [in] DWORD dwFlags,
  [in] DWORD th32ProcessID
);

在进程快照信息中,包含着进程导入模块的信息。因此,我们可以有如下实现思路:

  1. 调用CreateToolhelp32Snapshot指定TH32CS_SNAPPROCESS属性,获取进程快照句柄。
  2. 使用Process32Next遍历进程信息,对比进程名查找到目标进程。
  3. 使用OpenProcess验证目标进程状态。
  4. 调用CreateToolhelp32Snapshot指定TH32CS_SNAPMODULE属性,获取目标进程的模块快照。
  5. 使用Module32Next遍历模块,直到获取到目标模块信息,返回目标模块的句柄。
  6. 后续干什么都可以了,例如使用GetProcAddress获取目标函数的地址。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <Windows.h>
#include <Tlhelp32.h>
#include <tchar.h>
#include <string>
#include <stdio.h>
 
HMODULE GetProcessModuleHandle(DWORD pid, CONST TCHAR* moduleName) {    // 根据 PID 、模块名(需要写后缀,如:".dll"),获取模块入口地址
    MODULEENTRY32 moduleEntry;
    HANDLE handle = NULL;
    moudleInfoHandle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); //  获取进程快照的打开句柄,包含模块信息(TH32CS_SNAPMODULE指定)
    if (!moudleInfoHandle) {
        CloseHandle(moudleInfoHandle);
        return NULL;
    }
    ZeroMemory(&moduleEntry, sizeof(MODULEENTRY32));
    moduleEntry.dwSize = sizeof(MODULEENTRY32);
    if (!Module32First(moudleInfoHandle, &moduleEntry)) {
        CloseHandle(moudleInfoHandle);
        return NULL;
    }
    do {
        if (_tcscmp(moduleEntry.szModule, moduleName) == 0) {
            CloseHandle(moudleInfoHandle);
            return moduleEntry.hModule;
        }
    } while (Module32Next(moudleInfoHandle, &moduleEntry));
    CloseHandle(moudleInfoHandle);
    return 0;
}
 
int main() {
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  // 进程快照句柄
    PROCESSENTRY32 process = {
        sizeof(PROCESSENTRY32)
    };  // 存放进程快照的结构体
 
    //  遍历进程
    while (Process32Next(hProcessSnap, &process)) {
        // 找到目标进程
        std::string s_szExeFile = process.szExeFile; // char* 转 string
        if (s_szExeFile == "xxx.exe") {
            HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
            if (hProcess)
            {
                HMODULE hMod = GetProcessModuleHandle(process.th32ProcessID, "xxx.dll");
                if (hMod)
                {
                    auto fnAddress = GetProcAddress(hMod, "xxFunc");
                     
                    std::cout << fnAddress <<"        "<< GetLastError();
                }
            }
        }
    }
}

2. 枚举进程模块

按照微软官方的建议,使用EnumProcessModules函数枚举进程模块可以确定哪些进程加载了特定的DLL。这个函数在psapi.h中。以下是微软给出的实例代码。

1
2
3
4
5
6
BOOL EnumProcessModules(
  [in]  HANDLE  hProcess,
  [out] HMODULE *lphModule,
  [in]  DWORD   cb,
  [out] LPDWORD lpcbNeeded
);
  1. 根据进程ID,调用OpenProcess获取进程句柄。
  2. 调用EnumProcessModules函数枚举模块信息。模块句柄都返回到hMods数组中。进一步筛选即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <psapi.h>
 
// 为了确保正确解析符号,需要将 Psapi.lib 添加到 TARGETLIBS,并使用 -DPSAPI_VERSION=1 编译
 
int PrintModules( DWORD processID )
{
    HMODULE hMods[1024];
    HANDLE hProcess;
    DWORD cbNeeded;
    unsigned int i;
 
    // 打印进程标识符。
 
    printf( "\n进程 ID:%u\n", processID );
 
    // 获取进程的句柄。
 
    hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
                            PROCESS_VM_READ,
                            FALSE, processID );
    if (NULL == hProcess)
        return 1;
    // 获取此进程中所有模块的列表。
 
    if( EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
    {
        for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
        {
            TCHAR szModName[MAX_PATH];
 
            // 获取模块文件的完整路径。
 
            if ( GetModuleFileNameEx( hProcess, hMods[i], szModName,sizeof(szModName) / sizeof(TCHAR)))
            {
                // 打印模块名和句柄值。
 
                _tprintf( TEXT("\t%s (0x%08X)\n"), szModName, hMods[i] );
            }
        }
    }
 
    // 释放对进程的句柄。
 
    CloseHandle( hProcess );
 
    return 0;
}
 
int main( void )
{
 
    DWORD aProcesses[1024];
    DWORD cbNeeded;
    DWORD cProcesses;
    unsigned int i;
 
    // 获取进程标识符的列表。
 
    if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
        return 1;
 
    // 计算返回了多少个进程标识符。
 
    cProcesses = cbNeeded / sizeof(DWORD);
 
    // 打印每个进程的模块名称。
 
    for ( i = 0; i < cProcesses; i++ )
    {
        PrintModules( aProcesses[i] );
    }
 
    return 0;
}

3. 获取PEB

PEB +0x00c成员Ldr指向_PEB_LDR_DATA结构,此结构的第三成员InMemoryOrderModuleList包含进程的已加载模块的双向链表的头部。列表中的每个项目都是指向LDR_DATA_TABLE_ENTRY结构的指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct _LDR_DATA_TABLE_ENTRY {
    PVOID Reserved1[2];
    LIST_ENTRY InMemoryOrderLinks;
    PVOID Reserved2[2];
    PVOID DllBase;
    PVOID EntryPoint;
    PVOID Reserved3;
    UNICODE_STRING FullDllName;
    BYTE Reserved4[8];
    PVOID Reserved5[3];
    union {
        ULONG CheckSum;
        PVOID Reserved6;
    };
    ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

因此,这种方法的思路如下:

  1. 调用NtWow64QueryInformationProcess64获取PROCESS_BASIC_INFORMATION64(32)结构
  2. 调用NtWow64ReadVirtualMemory64(32位用ReadProcessMemory)读出PebBaseAddress
  3. 获取到PEB,定位到_PEB_LDR_DATA遍历_LDR_DATA_TABLE_ENTRY
  4. 通过FullDllName筛选,DllBase返回模块基地址。

贴一个大佬的获取PEB代码(原谅我实在忘了在哪找到的,知道的朋友请留言一下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
#include "stdafx.h"
 
#include <iostream>
#include <windows.h>
#include <subauth.h>
 
#pragma region 依赖
 
#define NT_SUCCESS(x) ((x) >= 0)
#define ProcessBasicInformation 0
 
typedef
NTSTATUS(WINAPI *pfnNtWow64QueryInformationProcess64)
(HANDLE ProcessHandle, UINT32 ProcessInformationClass,
    PVOID ProcessInformation, UINT32 ProcessInformationLength,
    UINT32* ReturnLength);
  
typedef
NTSTATUS(WINAPI *pfnNtWow64ReadVirtualMemory64)
(HANDLE ProcessHandle, PVOID64 BaseAddress,
    PVOID BufferData, UINT64 BufferLength,
    PUINT64 ReturnLength);
  
typedef
NTSTATUS(WINAPI *pfnNtQueryInformationProcess)
(HANDLE ProcessHandle, ULONG ProcessInformationClass,
    PVOID ProcessInformation, UINT32 ProcessInformationLength,
    UINT32* ReturnLength);
  
template <typename T>
struct _UNICODE_STRING_T
{
    WORD Length;
    WORD MaximumLength;
    T Buffer;
};
  
template <typename T>
struct _LIST_ENTRY_T
{
    T Flink;
    T Blink;
};
  
template <typename T, typename NGF, int A>
struct _PEB_T
{
    typedef T type;
  
    union
    {
        struct
        {
            BYTE InheritedAddressSpace;
            BYTE ReadImageFileExecOptions;
            BYTE BeingDebugged;
            BYTE BitField;
        };
        T dummy01;
    };
    T Mutant;
    T ImageBaseAddress;
    T Ldr;
    T ProcessParameters;
    T SubSystemData;
    T ProcessHeap;
    T FastPebLock;
    T AtlThunkSListPtr;
    T IFEOKey;
    T CrossProcessFlags;
    T UserSharedInfoPtr;
    DWORD SystemReserved;
    DWORD AtlThunkSListPtr32;
    T ApiSetMap;
    T TlsExpansionCounter;
    T TlsBitmap;
    DWORD TlsBitmapBits[2];
    T ReadOnlySharedMemoryBase;
    T HotpatchInformation;
    T ReadOnlyStaticServerData;
    T AnsiCodePageData;
    T OemCodePageData;
    T UnicodeCaseTableData;
    DWORD NumberOfProcessors;
    union
    {
        DWORD NtGlobalFlag;
        NGF dummy02;
    };
    LARGE_INTEGER CriticalSectionTimeout;
    T HeapSegmentReserve;
    T HeapSegmentCommit;
    T HeapDeCommitTotalFreeThreshold;
    T HeapDeCommitFreeBlockThreshold;
    DWORD NumberOfHeaps;
    DWORD MaximumNumberOfHeaps;
    T ProcessHeaps;
    T GdiSharedHandleTable;
    T ProcessStarterHelper;
    T GdiDCAttributeList;
    T LoaderLock;
    DWORD OSMajorVersion;
    DWORD OSMinorVersion;
    WORD OSBuildNumber;
    WORD OSCSDVersion;
    DWORD OSPlatformId;
    DWORD ImageSubsystem;
    DWORD ImageSubsystemMajorVersion;
    T ImageSubsystemMinorVersion;
    T ActiveProcessAffinityMask;
    T GdiHandleBuffer[A];
    T PostProcessInitRoutine;
    T TlsExpansionBitmap;
    DWORD TlsExpansionBitmapBits[32];
    T SessionId;
    ULARGE_INTEGER AppCompatFlags;
    ULARGE_INTEGER AppCompatFlagsUser;
    T pShimData;
    T AppCompatInfo;
    _UNICODE_STRING_T<T> CSDVersion;
    T ActivationContextData;
    T ProcessAssemblyStorageMap;
    T SystemDefaultActivationContextData;
    T SystemAssemblyStorageMap;
    T MinimumStackCommit;
    T FlsCallback;
    _LIST_ENTRY_T<T> FlsListHead;
    T FlsBitmap;
    DWORD FlsBitmapBits[4];
    T FlsHighIndex;
    T WerRegistrationData;
    T WerShipAssertPtr;
    T pContextData;
    T pImageHeaderHash;
    T TracingFlags;
    T CsrServerReadOnlySharedMemoryBase;
};
  
typedef _PEB_T<DWORD, DWORD64, 34> _PEB32;
typedef _PEB_T<DWORD64, DWORD, 30> _PEB64;
  
typedef struct _STRING_32
{
    WORD Length;
    WORD MaximumLength;
    UINT32 Buffer;
} STRING32, *PSTRING32;
  
typedef struct _STRING_64
{
    WORD Length;
    WORD MaximumLength;
    UINT64 Buffer;
} STRING64, *PSTRING64;
  
typedef struct _RTL_DRIVE_LETTER_CURDIR_32
{
    WORD Flags;
    WORD Length;
    ULONG TimeStamp;
    STRING32 DosPath;
} RTL_DRIVE_LETTER_CURDIR32, *PRTL_DRIVE_LETTER_CURDIR32;
  
typedef struct _RTL_DRIVE_LETTER_CURDIR_64
{
    WORD Flags;
    WORD Length;
    ULONG TimeStamp;
    STRING64 DosPath;
} RTL_DRIVE_LETTER_CURDIR64, *PRTL_DRIVE_LETTER_CURDIR64;
  
typedef struct _UNICODE_STRING_32
{
    WORD Length;
    WORD MaximumLength;
    UINT32 Buffer;
} UNICODE_STRING32, *PUNICODE_STRING32;
  
typedef struct _UNICODE_STRING_64
{
    WORD Length;
    WORD MaximumLength;
    UINT64 Buffer;
} UNICODE_STRING64, *PUNICODE_STRING64;
  
  
typedef struct _CURDIR_32
{
    UNICODE_STRING32 DosPath;
    UINT32 Handle;
} CURDIR32, *PCURDIR32;
  
typedef struct _RTL_USER_PROCESS_PARAMETERS_32
{
    ULONG MaximumLength;
    ULONG Length;
    ULONG Flags;
    ULONG DebugFlags;
    UINT32 ConsoleHandle;
    ULONG ConsoleFlags;
    UINT32 StandardInput;
    UINT32 StandardOutput;
    UINT32 StandardError;
    CURDIR32 CurrentDirectory;
    UNICODE_STRING32 DllPath;
    UNICODE_STRING32 ImagePathName;
    UNICODE_STRING32 CommandLine;
    UINT32 Environment;
    ULONG StartingX;
    ULONG StartingY;
    ULONG CountX;
    ULONG CountY;
    ULONG CountCharsX;
    ULONG CountCharsY;
    ULONG FillAttribute;
    ULONG WindowFlags;
    ULONG ShowWindowFlags;
    UNICODE_STRING32 WindowTitle;
    UNICODE_STRING32 DesktopInfo;
    UNICODE_STRING32 ShellInfo;
    UNICODE_STRING32 RuntimeData;
    RTL_DRIVE_LETTER_CURDIR32 CurrentDirectores[32];
    ULONG EnvironmentSize;
} RTL_USER_PROCESS_PARAMETERS32, *PRTL_USER_PROCESS_PARAMETERS32;
  
  
typedef struct _CURDIR_64
{
    UNICODE_STRING64 DosPath;
    UINT64 Handle;
} CURDIR64, *PCURDIR64;
  
typedef struct _RTL_USER_PROCESS_PARAMETERS_64
{
    ULONG MaximumLength;
    ULONG Length;
    ULONG Flags;
    ULONG DebugFlags;
    UINT64 ConsoleHandle;
    ULONG ConsoleFlags;
    UINT64 StandardInput;
    UINT64 StandardOutput;
    UINT64 StandardError;
    CURDIR64 CurrentDirectory;
    UNICODE_STRING64 DllPath;
    UNICODE_STRING64 ImagePathName;
    UNICODE_STRING64 CommandLine;
    UINT64 Environment;
    ULONG StartingX;
    ULONG StartingY;
    ULONG CountX;
    ULONG CountY;
    ULONG CountCharsX;
    ULONG CountCharsY;
    ULONG FillAttribute;
    ULONG WindowFlags;
    ULONG ShowWindowFlags;
    UNICODE_STRING64 WindowTitle;
    UNICODE_STRING64 DesktopInfo;
    UNICODE_STRING64 ShellInfo;
    UNICODE_STRING64 RuntimeData;
    RTL_DRIVE_LETTER_CURDIR64 CurrentDirectores[32];
    ULONG EnvironmentSize;
} RTL_USER_PROCESS_PARAMETERS64, *PRTL_USER_PROCESS_PARAMETERS64;
  
  
  
typedef struct _PROCESS_BASIC_INFORMATION64 {
    NTSTATUS ExitStatus;
    UINT32 Reserved0;
    UINT64 PebBaseAddress;
    UINT64 AffinityMask;
    UINT32 BasePriority;
    UINT32 Reserved1;
    UINT64 UniqueProcessId;
    UINT64 InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION64;
  
typedef struct _PROCESS_BASIC_INFORMATION32 {
    NTSTATUS ExitStatus;
    UINT32 PebBaseAddress;
    UINT32 AffinityMask;
    UINT32 BasePriority;
    UINT32 UniqueProcessId;
    UINT32 InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION32;
 
#pragma endregion
 
int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE m_ProcessHandle =
        OpenProcess(
            PROCESS_ALL_ACCESS,     // 所有权限
            FALSE,                  // 不继承句柄
            8016                    // 进程ID,此处为了方便直接写死
        );
  
    BOOL bSource = FALSE;           // 判断自身进程是否为 64位
    BOOL bTarget = FALSE;           // 判断目标进程是否为 64位
    IsWow64Process(
        GetCurrentProcess(),        // 进程句柄
        &bSource                    // 用来接收返回值的变量,64位 FLASE | 32位 TRUE
        );
    IsWow64Process(
        m_ProcessHandle,            // 进程句柄
        &bTarget                    // 用来接收返回值的变量,64位 FLASE | 32位 TRUE
        );
 
    // 目标 64位,自身 32位
    if(bTarget == FALSE && bSource == TRUE)
    {
        // 获取 ntdll.dll 模块句柄
        HMODULE NtdllModule = GetModuleHandle("ntdll.dll");
 
        pfnNtWow64QueryInformationProcess64 NtWow64QueryInformationProcess64 = (pfnNtWow64QueryInformationProcess64)GetProcAddress(NtdllModule,"NtWow64QueryInformationProcess64");
        pfnNtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = (pfnNtWow64ReadVirtualMemory64)GetProcAddress(NtdllModule,"NtWow64ReadVirtualMemory64");
        PROCESS_BASIC_INFORMATION64 pbi = {0};
        UINT64 ReturnLength = 0;
        NTSTATUS Status = NtWow64QueryInformationProcess64(m_ProcessHandle,ProcessBasicInformation,&pbi,(UINT32)sizeof(pbi),(UINT32*)&ReturnLength);
  
        if (NT_SUCCESS(Status)){
            _PEB64* Peb = (_PEB64*)malloc(sizeof(_PEB64));
            RTL_USER_PROCESS_PARAMETERS64* ProcessParameters = (RTL_USER_PROCESS_PARAMETERS64*)malloc(sizeof(RTL_USER_PROCESS_PARAMETERS64));
            Status = NtWow64ReadVirtualMemory64(m_ProcessHandle,(PVOID64)pbi.PebBaseAddress,(_PEB64*)Peb,sizeof(_PEB64),&ReturnLength);
             
            std::cout << "PEB地址:" << std::hex << pbi.PebBaseAddress << std::endl;
            //cout << "Ldr:" << hex << Peb->Ldr << endl;
            //cout << "ImageBaseAddress:" << hex << Peb->ImageBaseAddress << endl;
        }
    }
  
    // 目标 32位,自身 32位
    else if (bTarget == TRUE && bSource == TRUE)
    {
        HMODULE NtdllModule = GetModuleHandle("ntdll.dll");
        pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(NtdllModule,"NtQueryInformationProcess");
        PROCESS_BASIC_INFORMATION32 pbi = {0};
        UINT32  ReturnLength = 0;
        NTSTATUS Status = NtQueryInformationProcess(m_ProcessHandle,ProcessBasicInformation,&pbi,(UINT32)sizeof(pbi),(UINT32*)&ReturnLength);
         
        if (NT_SUCCESS(Status)){
            _PEB32* Peb = (_PEB32*)malloc(sizeof(_PEB32));
            ReadProcessMemory(m_ProcessHandle, (PVOID)pbi.PebBaseAddress,(_PEB32*)Peb,sizeof(_PEB32),NULL);
            
            std::cout << "PEB地址:" << std::hex << pbi.PebBaseAddress << std::endl;
            //printf("LdrAddress:%x\r\n", ((_PEB32*)Peb)->Ldr);
            //printf("ImageBaseAddress:%x\r\n", ((_PEB32*)Peb)->ImageBaseAddress);
        }
    }
 
    getchar();
    return 0;
}

4. 注入

对目标进程进行DLL注入,Hook GetMoudleHandleLoadlibary等函数,让目标进程自己调用,进行IPC通信。

参考

PEB (winternl.h) - Win32 应用 |Microsoft 学习

PEB_LDR_DATA (winternl.h) - Win32 应用 |Microsoft 学习

PEB及LDR链 - bokernb - 博客园 (cnblogs.com)

远程获取进程DLL模块地址_获取进程模块-CSDN博客

CreateToolhelp32Snapshot 函数 (tlhelp32.h) - Win32 apps | Microsoft Learn

枚举进程的所有模块 - Win32 apps | Microsoft Learn


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
点赞7
打赏
分享
最新回复 (4)
雪    币: 9476
活跃值: (4393)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
lononan 2023-12-14 02:38
2
0
还有一种ZwQueryVirtualMemory查询MemoryBasicInformation->MEM_IMAGE,再ZwQueryVirtualMemory查询MemorySectionName->MEMORY_SECTION_NAME
雪    币: 19349
活跃值: (28971)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-12-14 09:16
3
1
感谢分享
雪    币: 3698
活跃值: (4091)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sonyps 2023-12-14 13:02
4
0
第二种和第三种实际上是同一种
雪    币: 2739
活跃值: (2366)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiwushgya 2023-12-14 14:37
5
0
高手,谢谢大佬分享
游客
登录 | 注册 方可回帖
返回