首页
社区
课程
招聘
1
[原创]某上市驱动以修改早期UC无附加读源码而稳定读方法
发表于: 2025-2-16 03:49 4557

[原创]某上市驱动以修改早期UC无附加读源码而稳定读方法

2025-2-16 03:49
4557

引言

很久很久以前UC公开了一篇读写方法:https://www.unknowncheats.me/forum/anti-cheat-bypass/444289-read-process-physical-memory-attach.html

某上市驱动

修改其中一部分
直接上伪代码 "记得刷页 记得刷页 记得刷页"

伪代码IDA版本

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
NTSTATUS __fastcall readmem(
        HANDLE ProcessId,
        __int64 TargetAddress,
        signed __int64 Size,
        char *SourceAddress,
        __int64 Flag)
{
  char *pSourceBuffer; // r13
  signed __int64 BytesToCopy; // r14
  __int64 DstAddress; // rsi
  NTSTATUS ntStatus; // eax
  __int64 ProcessCr3; // rdi
  int BuildNumber; // eax
  char FlagValue; // fl
  int Index; // r8d
  __int64 IndexOffset; // rdx
  char *pInternalBuffer; // r15
  char *pMappingAddress; // r11
  __int64 BytesRemaining; // r10
  unsigned __int64 *pPTE; // rdx
  char _AH; // ah
  char _CL; // cl
  __int64 PageTableBase_1; // r14
  __int64 cpy_already; // r13
  unsigned __int64 VirtualAddress; // r9
  __int64 PML4EIndex; // rcx
  __int64 PDPTEntry; // rcx
  __int64 v28; // r8
  __int64 v29; // rdi
  __int64 v30; // rcx
  __int64 v31; // r9
  __int64 v32; // rcx
  __int64 v33; // rdi
  unsigned __int64 v34; // r8
  char *v35; // rsi
  __int64 v36; // rax
  char *v37; // rax
  char *v38; // rdi
  char _SI; // si
  PEPROCESS TargetProcess; // [rsp-60h] [rbp-68h] BYREF
  __int64 TempPTE; // [rsp-58h] [rbp-60h] BYREF
  __int64 ProcessCr3buffer; // [rsp-50h] [rbp-58h]
  unsigned __int64 v43; // [rsp-48h] [rbp-50h]
  __int64 CurrentIrql; // [rsp-40h] [rbp-48h]
  int v45; // [rsp+10h] [rbp+8h]
 
  pSourceBuffer = SourceAddress;
  BytesToCopy = Size;
  DstAddress = TargetAddress;
  if ( !ProcessId || !TargetAddress || !SourceAddress || (unsigned __int64)(Size - 1) > 0xFFF )
    return 0xC0000001;
  if ( !MmAllocateMappingAddress_MEM )          // // 初始化映射地址空间和缓冲区(如果尚未初始化)
    MmAllocateMappingAddress_MEM = (__int64)MmAllocateMappingAddress(0x200000ui64, 1u);// 分配 2MB 的映射地址空间
  if ( !ExAllocatePoolWithTag_mem )
    ExAllocatePoolWithTag_mem = (__int64)ExAllocatePoolWithTag(NonPagedPool, 0x200000ui64, 1u);// 分配 2MB 的非分页内存池
  if ( !qword_12D48 )
    qword_12D48 = *(__int64 *)((char *)&MmGetVirtualForPhysical + 0x22);// 获取用于虚拟地址到物理地址转换的内核变量
  TargetProcess = 0i64;
  ntStatus = PsLookupProcessByProcessId(ProcessId, &TargetProcess);
  if ( ntStatus )
    return ntStatus;
  ProcessCr3 = GetCr3((__int64)TargetProcess);
  ProcessCr3buffer = ProcessCr3;
  ObfDereferenceObject(TargetProcess);
  BuildNumber = ((__int64 (*)(void))loc_1061)();// 获取构建号
  v45 = BuildNumber;
  Index = BuildNumber;
  if ( BuildNumber == -1 )
    return 0xC0000001;
  IndexOffset = BuildNumber << 12;              //  计算临时缓冲区和映射地址的偏移
  pInternalBuffer = (char *)(IndexOffset + ExAllocatePoolWithTag_mem);
  if ( Flag )                                   // 根据 Flag 预先复制数据到内部缓冲区
  {
    qmemcpy(pInternalBuffer, pSourceBuffer, BytesToCopy);
    DstAddress = TargetAddress;
    ProcessCr3 = ProcessCr3buffer;
  }
  pMappingAddress = (char *)(IndexOffset + MmAllocateMappingAddress_MEM);// 计算映射地址
  BytesRemaining = BytesToCopy;                 // 计算 PTE 指针
  pPTE = (unsigned __int64 *)(qword_12D48
                            + (((unsigned __int64)(IndexOffset + MmAllocateMappingAddress_MEM) >> 9) & 0x7FFFFFFFF8i64));
  v43 = *pPTE;                                  // 保存原始 PTE
  _AH = FlagValue;
  _disable();                                   // 禁用中断并提升 IRQL
  __asm { rcl     ah, 96h }
  CurrentIrql = KeGetCurrentIrql();
  __writecr8(2ui64);                            // 将 IRQL 设置为 DISPATCH_LEVEL
  if ( BytesToCopy > 0 )                        // 循环遍历内存页,逐页复制数据
  {
    _CL = -79;
    __asm
    {
      rcr     r9w, cl
      rcl     r9w, 3Ch
    }
    PageTableBase_1 = ProcessCr3 & 0xFFFFFFFFFF000i64;// 获取页目录基地址的低 48
    cpy_already = 0i64;
    while ( 1 )
    {
      VirtualAddress = DstAddress + cpy_already;//  当前要处理的虚拟地址
      TempPTE = 0i64;
      PML4EIndex = ((unsigned __int64)(DstAddress + cpy_already) >> 39) & 0x1FF;
      *pPTE = (PageTableBase_1 + 8 * PML4EIndex) & 0xFFFFFFFFFFFFF000ui64 | 0x1E3;
      __invlpg(pMappingAddress);                //  TLB 中对应的条目失效
      qmemcpy(&TempPTE, &pMappingAddress[8 * PML4EIndex], sizeof(TempPTE));// 读取 PML4E
                                                //
      PDPTEntry = TempPTE;
      if ( (TempPTE & 1) == 0
        || ((ProcessCr3buffer ^ TempPTE) & 0xFFFFFFFFFF000i64) == 0
        || (TempPTE = 0i64,
            v28 = (PDPTEntry & 0xFFFFFFFFFF000i64) + 8 * ((VirtualAddress >> 30) & 0x1FF),
            *pPTE = v28 & 0xFFFFFFFFFFFFF000ui64 | 0x1E3,
            __invlpg(pMappingAddress),
            qmemcpy(&TempPTE, &pMappingAddress[v28 & 0xFFF], sizeof(TempPTE)),
            v29 = TempPTE,
            (TempPTE & 1) == 0) )
      {
LABEL_44:
        BytesToCopy = Size;
        pSourceBuffer = SourceAddress;
        Index = v45;
        break;
      }
      if ( (TempPTE & 0x80u) == 0i64 )
      {
        TempPTE = 0i64;
        v28 = (v29 & 0xFFFFFFFFFF000i64) + 8 * ((VirtualAddress >> 21) & 0x1FF);
        *pPTE = v28 & 0xFFFFFFFFFFFFF000ui64 | 0x1E3;
        __invlpg(pMappingAddress);
        qmemcpy(&TempPTE, &pMappingAddress[v28 & 0xFFF], sizeof(TempPTE));
        v29 = TempPTE;
        if ( (TempPTE & 1) == 0 )
          goto LABEL_44;
        if ( (TempPTE & 0x80u) == 0i64 )
        {
          TempPTE = 0i64;
          v28 = (v29 & 0xFFFFFFFFFF000i64) + 8 * ((VirtualAddress >> 12) & 0x1FF);
          *pPTE = v28 & 0xFFFFFFFFFFFFF000ui64 | 0x1E3;
          __invlpg(pMappingAddress);
          qmemcpy(&TempPTE, &pMappingAddress[v28 & 0xFFF], sizeof(TempPTE));
          if ( (TempPTE & 1) == 0 )
            goto LABEL_44;
          if ( (TempPTE & 2) != 0 )
            v28 = 0i64;
          v32 = (VirtualAddress & 0xFFF) + (TempPTE & 0xFFFFFFFFFF000i64);
          goto LABEL_32;
        }
        v30 = TempPTE & 0xFFFFFFFE00000i64;
        v31 = VirtualAddress & 0x1FFFFF;
      }
      else
      {
        v30 = TempPTE & 0xFFFFFC0000000i64;
        v31 = VirtualAddress & 0x3FFFFFFF;
      }
      v32 = v30 + v31;
      if ( (v29 & 2) != 0 )
        v28 = 0i64;
LABEL_32:
      if ( v32 && (!v28 || Flag != 1) )
      {
        v33 = v32 & 0xFFF;
        v34 = BytesRemaining;
        if ( 4096 - v33 < (unsigned __int64)BytesRemaining )
          v34 = 4096 - v33;
        if ( v34 )
        {
          v35 = &pInternalBuffer[cpy_already];
          v36 = 483i64;
          if ( Flag == 2 )
            v36 = 511i64;
          *pPTE = v32 & 0xFFFFFFFFFFFFF000ui64 | v36;
          __invlpg(pMappingAddress);
          v37 = &pMappingAddress[v33];
          if ( Flag )
          {
            v38 = &pMappingAddress[v33];
          }
          else
          {
            v38 = &pInternalBuffer[cpy_already];
            v35 = v37;
          }
          BytesRemaining -= v34;
          cpy_already += v34;
          qmemcpy(v38, v35, v34);
          _SI = (_BYTE)v35 + v34;
          __asm { rcl     sil, cl }
          DstAddress = TargetAddress;
          if ( BytesRemaining > 0 )
            continue;
        }
      }
      goto LABEL_44;
    }
  }
  *pPTE = v43;
  __invlpg(pMappingAddress);
  __writecr8((unsigned __int8)CurrentIrql);
  _enable();
  if ( !Flag )
    qmemcpy(pSourceBuffer, pInternalBuffer, BytesToCopy);
  memset(pInternalBuffer, 0, BytesToCopy);
  byte_12B40[Index] = 0;
  return -(int)BytesRemaining;
}

伪代码C++版本(可能有误)

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
#include <ntddk.h>
 
// 假设的全局变量,在实际驱动程序中需要正确初始化
extern PVOID  MmAllocateMappingAddress_MEM;
extern PVOID  ExAllocatePoolWithTag_mem;
extern PVOID qword_12D48;
extern CHAR byte_12B40[256]; // 假设的大小
 
// 假设的函数原型,这些函数在 ntoskrnl.exe 中
extern  NTSTATUS ObfDereferenceObject(PVOID Object);
extern  NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS* Process);
extern  PHYSICAL_ADDRESS MmGetPhysicalAddress(PVOID BaseAddress);
extern  PVOID MmGetVirtualForPhysical(PHYSICAL_ADDRESS PhysicalAddress);
extern  PVOID MmAllocateMappingAddress(SIZE_T NumberOfBytes, ULONG Tag);
extern  VOID MmFreeMappingAddress(PVOID BaseAddress, ULONG Tag);
extern  PVOID ExAllocatePoolWithTag(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag);
extern  VOID ExFreePool(PVOID P);
extern  KIRQL KeGetCurrentIrql();
extern  void _disable();
extern  void _enable();
extern  __int64 GetCr3(__int64 a1);
extern  int loc_1061(); // 假设的函数
 
//将内联汇编改写成C/C++
#define Barrier() _ReadWriteBarrier()
#define  __invlpg(addr) { \
    __try { \
        ProbeForRead(addr, 1, 1); \
    } __except (EXCEPTION_EXECUTE_HANDLER) {} \
    }
 
NTSTATUS tlb_relate(
    HANDLE ProcessId,
    PVOID TargetAddress,
    SIZE_T Size,
    PVOID SourceAddress,
    ULONG Flag)
{
    // 检查参数有效性
    if (!ProcessId || !TargetAddress || !SourceAddress || (Size - 1) > 0xFFF) {
        return STATUS_INVALID_PARAMETER;
    }
 
    // 1. 获取目标进程的 EPROCESS
    PEPROCESS TargetProcess = nullptr;
    NTSTATUS status = PsLookupProcessByProcessId(ProcessId, &TargetProcess);
    if (!NT_SUCCESS(status)) {
        return status;
    }
 
    // 2. 获取目标进程的 CR3
    __int64 ProcessCr3 = GetCr3((__int64)TargetProcess);
    __int64 OriginalCr3 = ProcessCr3; // 保存原始 CR3 值
    ObfDereferenceObject(TargetProcess);
 
    //获取构建号
    int BuildNumber = loc_1061();
    if (BuildNumber == -1) {
        return STATUS_INVALID_PARAMETER;
    }
 
    // 3. 初始化内部缓冲区和映射地址空间
    if (!MmAllocateMappingAddress_MEM)
    {
        MmAllocateMappingAddress_MEM = MmAllocateMappingAddress(0x200000, 'MyTg');  //使用'MyTg'作为tag
    }
 
    if (!ExAllocatePoolWithTag_mem)
    {
        ExAllocatePoolWithTag_mem = ExAllocatePoolWithTag(NonPagedPool, 0x200000, 'MyTg'); //使用'MyTg'作为tag
    }
 
    if (!MmAllocateMappingAddress_MEM || !ExAllocatePoolWithTag_mem)
    {
        if (MmAllocateMappingAddress_MEM) {
            MmFreeMappingAddress(MmAllocateMappingAddress_MEM, 'MyTg');
            MmAllocateMappingAddress_MEM = nullptr; // 避免double free
        }
        if (ExAllocatePoolWithTag_mem)
        {
            ExFreePool(ExAllocatePoolWithTag_mem);
            ExAllocatePoolWithTag_mem = nullptr; // 避免 double free
        }
        return STATUS_INSUFFICIENT_RESOURCES;
    }
 
    if (!qword_12D48)
    {
        qword_12D48 = *reinterpret_cast<PVOID*>(reinterpret_cast<char*>(MmGetVirtualForPhysical) + 0x22);
    }
 
    //计算在缓冲区内的偏移
    __int64 IndexOffset = (__int64)BuildNumber << 12;
    char* pInternalBuffer = reinterpret_cast<char*>(ExAllocatePoolWithTag_mem) + IndexOffset;
    char* pMappingAddress = reinterpret_cast<char*>(MmAllocateMappingAddress_MEM) + IndexOffset;
 
    // 4. 根据 Flag 预复制数据
    if (Flag && (Flag != 1)) {
        RtlCopyMemory(pInternalBuffer, SourceAddress, Size);
    }
 
    // 5. 提升 IRQL 并禁用中断 (进入关键区)
    KIRQL OldIrql = KeGetCurrentIrql();
    if (OldIrql < DISPATCH_LEVEL) {
        KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
    }
 
    // 6. 遍历页表
    SIZE_T BytesRemaining = Size;
    SIZE_T BytesCopied = 0;
 
    while (BytesRemaining > 0) {
        PVOID CurrentVirtualAddress = reinterpret_cast<char*>(TargetAddress) + BytesCopied;
 
        // 6.1 计算页表索引
        ULONG64 PML4EIndex = ((ULONG64)CurrentVirtualAddress >> 39) & 0x1FF;
        ULONG64 PDPEIndex = ((ULONG64)CurrentVirtualAddress >> 30) & 0x1FF;
        ULONG64 PDEIndex = ((ULONG64)CurrentVirtualAddress >> 21) & 0x1FF;
        ULONG64 PTEIndex = ((ULONG64)CurrentVirtualAddress >> 12) & 0x1FF;
        ULONG64 PageOffset = (ULONG64)CurrentVirtualAddress & 0xFFF;
 
        // 6.2 获取并修改 PTE
        ULONG64* pPTE = reinterpret_cast<ULONG64*>(reinterpret_cast<char*>(qword_12D48) + (((ULONG64)pMappingAddress >> 9) & 0x7FFFFFFFF8));
        Barrier();
        ULONG64 OriginalPTE = *pPTE;
 
 
        // 6.2.1 获取 PML4E
        *pPTE = (ProcessCr3 & 0xFFFFFFFFFF000ULL) | (PML4EIndex << 3) | 0x1E3;
        __invlpg(pMappingAddress);
        Barrier();
        ULONG64 PML4E = *reinterpret_cast<PULONG64>(pMappingAddress + (PML4EIndex * sizeof(ULONG64)));
 
        if (!(PML4E & 1) || ((OriginalCr3 ^ PML4E) & 0xFFFFFFFFFF000ULL) == 0)
        {
            goto Cleanup;
        }
 
        // 6.2.2 获取 PDPE
        *pPTE = (PML4E & 0xFFFFFFFFFF000ULL) | (PDPEIndex << 3) | 0x1E3;
        __invlpg(pMappingAddress);
        Barrier();
        ULONG64 PDPE = *reinterpret_cast<PULONG64>(pMappingAddress + (PDPEIndex * sizeof(ULONG64)));
        if (!(PDPE & 1))
        {
            goto Cleanup;
        }
 
        if (!(PDPE & 0x80))  // 如果不是大页(1GB)
        {
            // 6.2.3 获取 PDE
            *pPTE = (PDPE & 0xFFFFFFFFFF000ULL) | (PDEIndex << 3) | 0x1E3;
            __invlpg(pMappingAddress);
            Barrier();
            ULONG64 PDE = *reinterpret_cast<PULONG64>(pMappingAddress + (PDEIndex * sizeof(ULONG64)));
 
            if (!(PDE & 1)) //检查有效位
            {
                goto Cleanup;
            }
 
            if (!(PDE & 0x80)) // 如果不是大页 (2MB)
            {
                // 6.2.4 获取 PTE
                *pPTE = (PDE & 0xFFFFFFFFFF000ULL) | (PTEIndex << 3) | 0x1E3;
                __invlpg(pMappingAddress);
                Barrier();
                ULONG64 PTE = *reinterpret_cast<PULONG64>(pMappingAddress + (PTEIndex * sizeof(ULONG64)));
 
                if (!(PTE & 1))  //检查有效位
                {
                    goto Cleanup;
                }
 
                // 6.2.5 4KB 页复制
                PHYSICAL_ADDRESS PhysicalAddress;
                PhysicalAddress.QuadPart = (PTE & 0xFFFFFFFFFF000ULL) | PageOffset;
 
                // 设置 PTE 为可读写等
                ULONG64 PTEFlags = 483;
                if (Flag == 2)
                {
                    PTEFlags = 511;
                }
                *pPTE = PhysicalAddress.QuadPart & 0xFFFFFFFFFFFFF000ULL | PTEFlags;
                __invlpg(pMappingAddress);
                Barrier();
 
                PVOID DestAddress = pMappingAddress + PageOffset;
                PVOID SrcAddress = nullptr;
 
                if (Flag == 0) { //
                    SrcAddress = pInternalBuffer + BytesCopied;
                }
                else { //
                    SrcAddress = DestAddress;
                    DestAddress = pInternalBuffer + BytesCopied;
                }
 
 
                SIZE_T BytesToCopyInPage = min(4096 - PageOffset, BytesRemaining);
                RtlCopyMemory(DestAddress, SrcAddress, BytesToCopyInPage);
                BytesRemaining -= BytesToCopyInPage;
                BytesCopied += BytesToCopyInPage;
            }
            else
            {
                // 6.2.6 处理 2MB 大页
                PHYSICAL_ADDRESS PhysicalAddress;
                PhysicalAddress.QuadPart = (PDE & 0xFFFFFFFE00000ULL) | ((ULONG64)CurrentVirtualAddress & 0x1FFFFF);
 
                // 设置 PTE 为可读写等
                ULONG64 PTEFlags = 483;
                if (Flag == 2)
                {
                    PTEFlags = 511;
                }
                *pPTE = PhysicalAddress.QuadPart & 0xFFFFFFFFFFFFF000ULL | PTEFlags;
 
                __invlpg(pMappingAddress);
                Barrier();
 
                PVOID DestAddress = pMappingAddress + ((ULONG64)CurrentVirtualAddress & 0xFFF);
                PVOID SrcAddress = nullptr;
 
                if (Flag == 0) {  //
                    SrcAddress = pInternalBuffer + BytesCopied;
                }
                else { //
                    SrcAddress = DestAddress;
                    DestAddress = pInternalBuffer + BytesCopied;
                }
 
                SIZE_T BytesToCopyInPage = min(4096 - ((ULONG64)CurrentVirtualAddress & 0xFFF), BytesRemaining);
 
                RtlCopyMemory(DestAddress, SrcAddress, BytesToCopyInPage);
 
                BytesRemaining -= BytesToCopyInPage;
                BytesCopied += BytesToCopyInPage;
            }
        }
        else {
            //6.2.7 处理1GB
            PHYSICAL_ADDRESS PhysicalAddress;
            PhysicalAddress.QuadPart = (PDPE & 0xFFFFFC0000000ULL) | ((ULONG64)CurrentVirtualAddress & 0x3FFFFFFF);
 
            // 设置 PTE 为可读写等
            ULONG64 PTEFlags = 483;
            if (Flag == 2)
            {
                PTEFlags = 511;
            }
            *pPTE = PhysicalAddress.QuadPart & 0xFFFFFFFFFFFFF000ULL | PTEFlags;
 
            __invlpg(pMappingAddress);
            Barrier();
            PVOID DestAddress = pMappingAddress + ((ULONG64)CurrentVirtualAddress & 0xFFF);
            PVOID SrcAddress = nullptr;
 
            if (Flag == 0) {  //
                SrcAddress = pInternalBuffer + BytesCopied;
            }
            else { //
                SrcAddress = DestAddress;
                DestAddress = pInternalBuffer + BytesCopied;
            }
 
            SIZE_T BytesToCopyInPage = min(4096 - ((ULONG64)CurrentVirtualAddress & 0xFFF), BytesRemaining);
            RtlCopyMemory(DestAddress, SrcAddress, BytesToCopyInPage);
 
            BytesRemaining -= BytesToCopyInPage;
            BytesCopied += BytesToCopyInPage;
        }
    }
 
Cleanup:
    // 7. 恢复 PTE、IRQL 和中断
    *pPTE = OriginalPTE;
    __invlpg(pMappingAddress);
    Barrier();
 
    if (OldIrql < DISPATCH_LEVEL) {
        KeLowerIrql(OldIrql);
    }
 
    // 8. 如果 Flag 为 0,将数据从内部缓冲区复制到 SourceAddress
    if (Flag == 0) {
        RtlCopyMemory(SourceAddress, pInternalBuffer, Size);
    }
 
    // 9. 清空内部缓冲区, 设置标志位, 返回
    RtlZeroMemory(pInternalBuffer, Size);
    byte_12B40[BuildNumber] = 0;
    return (NTSTATUS)(BytesRemaining == 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}

[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 1
支持
分享
赞赏记录
参与人
雪币
留言
时间
木志本柯
+4
为你点赞!
2025-2-21 12:27
最新回复 (6)
雪    币: 4260
活跃值: (5525)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
这个应该是好多年的常识了吧 反正现在反作弊也都这么玩
2025-2-16 04:57
1
雪    币: 5071
活跃值: (5162)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
反作弊是依靠hook来检查是否被附加的吗?
2025-2-21 12:28
0
雪    币: 0
活跃值: (173)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
这种读取方式有个缺陷,如果物理内存换到磁盘上,就不行了
2025-2-21 14:16
0
雪    币: 5071
活跃值: (5162)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
qiepei 这种读取方式有个缺陷,如果物理内存换到磁盘上,就不行了
一般游戏外挂才会使用这个方法,一般游戏里的血量 人物坐标是实时都在使用的,所以一般不会缺页。
2025-2-21 14:23
0
雪    币: 62
活跃值: (408)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
木志本柯 反作弊是依靠hook来检查是否被附加的吗?
线程回调就可以吧
2025-2-24 22:01
0
雪    币: 39
活跃值: (514)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
mark
2025-3-2 11:53
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册