首页
社区
课程
招聘
[原创] Native API系列: 使用NtCreateUserProcess创建正常工作的进程
2022-5-14 22:05 23757

[原创] Native API系列: 使用NtCreateUserProcess创建正常工作的进程

2022-5-14 22:05
23757

Direct-NtCreateUserProcess

0x00 Prologue

最近以来, 使用Native API绕过AV/EDR的讨论似乎总保持着一定的热度, HellsGate后的各种衍生Gate, Syswhispers也从2进化到了3。这类技术的本质上比较相似, 动态获取目标功能号后, 再调用syscall指令从而native call。但发现一个现象, 研究者们似乎更倾向于使用NtCreateThread而非NtCreateProcess来验证他们的代码有效性。于是, 今年年初开始, 我开始针对进程创建的native call进行一系列研究。

 

进程创建的native call也并非崭新的话题, 需要4个native API即可满足需求:

  • NtCreateFile
  • NtCreateSection
  • NtCreateProcess(Ex)
  • NtCreateThread(Ex)

BlackHat 2017中的Process Doppelganging技术就是基于此诞生的。

 

而时至今日, NtCreateProcess在Win10时代只在系统进程创建时被调用, 用户进程的创建使用NtCreateUserProcess。这就是本文的主题, 围绕NtCreateUserProcess创建一个正常用户进程。

0x01 最简化实现

以下研究基于Windows10 21H2 (19044.1415)。

 

让我们从原理开始, 先看看Windows下创建用户进程的各个阶段 (Windows Internals 7th):

 

pic1

 

结合kernelbase和ntdll, 可以得出:

 

pic2

 

Stage1,5均在kernelbase!CreateProcessInternalW中实现。而我们关注的NtCreateUserProcess也是从CreateProcessInternalW中调用的:

 

pic3

 

默认情况下, ThreadFlags被赋值为1, 代表创建后线程暂停。

 

借助processhacker提供的头文件, NtCreateUserProcess的原型为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NTSYSCALLAPI
NTSTATUS
NTAPI
NtCreateUserProcess(
    _Out_ PHANDLE ProcessHandle,
    _Out_ PHANDLE ThreadHandle,
    _In_ ACCESS_MASK ProcessDesiredAccess,
    _In_ ACCESS_MASK ThreadDesiredAccess,
    _In_opt_ POBJECT_ATTRIBUTES ProcessObjectAttributes,
    _In_opt_ POBJECT_ATTRIBUTES ThreadObjectAttributes,
    _In_ ULONG ProcessFlags, // PROCESS_CREATE_FLAGS_*
    _In_ ULONG ThreadFlags, // THREAD_CREATE_FLAGS_*
    _In_opt_ PVOID ProcessParameters, // PRTL_USER_PROCESS_PARAMETERS
    _Inout_ PPS_CREATE_INFO CreateInfo,
    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList
);

这里我们关注最后3个参数:

  • ProcessParameters
  • CreateInfo
  • AttributeList

ProcessParameters

该参数的构建, 需要依靠另一个Native API: RtlCreateProcessParametersEx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NTSYSAPI
NTSTATUS
NTAPI
RtlCreateProcessParametersEx(
    _Out_ PRTL_USER_PROCESS_PARAMETERS *pProcessParameters,
    _In_ PUNICODE_STRING ImagePathName,
    _In_opt_ PUNICODE_STRING DllPath,
    _In_opt_ PUNICODE_STRING CurrentDirectory,
    _In_opt_ PUNICODE_STRING CommandLine,
    _In_opt_ PVOID Environment,
    _In_opt_ PUNICODE_STRING WindowTitle,
    _In_opt_ PUNICODE_STRING DesktopInfo,
    _In_opt_ PUNICODE_STRING ShellInfo,
    _In_opt_ PUNICODE_STRING RuntimeData,
    _In_ ULONG Flags // pass RTL_USER_PROC_PARAMS_NORMALIZED to keep parameters normalized
);

其中参数2ImagePathName为目标进程的Imag路径, 传入时该字符串必须以\\??\\为前缀。

 

函数返回值保存在参数1pProcessParameters。子进程的PEB的字段ProcessParameters保存此信息。

 

函数用法与在NtCreateProcess时期相同, 直接使用即可。

CreateInfo

结构体信息来自processhacker:

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
typedef struct _PS_CREATE_INFO
{
    SIZE_T Size;
    PS_CREATE_STATE State;
    union
    {
        // PsCreateInitialState
        struct
        {
            union
            {
                ULONG InitFlags;
                struct
                {
                    UCHAR WriteOutputOnExit : 1;
                    UCHAR DetectManifest : 1;
                    UCHAR IFEOSkipDebugger : 1;
                    UCHAR IFEODoNotPropagateKeyState : 1;
                    UCHAR SpareBits1 : 4;
                    UCHAR SpareBits2 : 8;
                    USHORT ProhibitedImageCharacteristics : 16;
                };
            };
            ACCESS_MASK AdditionalFileAccess;
        } InitState;
 
        // PsCreateFailOnSectionCreate
        struct
        {
            HANDLE FileHandle;
        } FailSection;
 
        // PsCreateFailExeFormat
        struct
        {
            USHORT DllCharacteristics;
        } ExeFormat;
 
        // PsCreateFailExeName
        struct
        {
            HANDLE IFEOKey;
        } ExeName;
 
        // PsCreateSuccess
        struct
        {
            union
            {
                ULONG OutputFlags;
                struct
                {
                    UCHAR ProtectedProcess : 1;
                    UCHAR AddressSpaceOverride : 1;
                    UCHAR DevOverrideEnabled : 1; // from Image File Execution Options
                    UCHAR ManifestDetected : 1;
                    UCHAR ProtectedProcessLight : 1;
                    UCHAR SpareBits1 : 3;
                    UCHAR SpareBits2 : 8;
                    USHORT SpareBits3 : 16;
                };
            };
            HANDLE FileHandle;
            HANDLE SectionHandle;
            ULONGLONG UserProcessParametersNative;
            ULONG UserProcessParametersWow64;
            ULONG CurrentParameterFlags;
            ULONGLONG PebAddressNative;
            ULONG PebAddressWow64;
            ULONGLONG ManifestAddress;
            ULONG ManifestSize;
        } SuccessState;
    };
} PS_CREATE_INFO, *PPS_CREATE_INFO;

这是个大有用处的结构体, 由状态, 结构体长度, 以及与状态对应union组成, 有2个状态是我们需要的:

状态 说明
InitState 0 调用`NtCreateUserProcess时作为参数, 应设置为该状态
SuccessState 6 调用`NtCreateUserProcess后, 成功时为该状态
 

初始化, 最简化的情况下, 只需要填入状态和大小即可:

1
2
createInfo.State = PsCreateInitialState;
createInfo.Size = sizeof(PS_CREATE_INFO);

成功状态的相关信息见下文。

AttributeList

属性列表, 结构体信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef struct _PS_ATTRIBUTE
{
    ULONG_PTR Attribute;
    SIZE_T Size;
    union
    {
        ULONG_PTR Value;
        PVOID ValuePtr;
    };
    PSIZE_T ReturnLength;
} PS_ATTRIBUTE, *PPS_ATTRIBUTE;
 
typedef struct _PS_ATTRIBUTE_LIST
{
    SIZE_T TotalLength;
    PS_ATTRIBUTE Attributes[1];
} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;

使用时, 根据TotalLength手动调整Attributes数组的大小。每个PS_ATTRIBUTE在x64下大小为0x20, 其中字段Attribute由宏PsAttributeValue提供:

1
2
3
4
5
#define PsAttributeValue(Number, Thread, Input, Additive) \
    (((Number) & PS_ATTRIBUTE_NUMBER_MASK) | \
    ((Thread) ? PS_ATTRIBUTE_THREAD : 0) | \
    ((Input) ? PS_ATTRIBUTE_INPUT : 0) | \
    ((Additive) ? PS_ATTRIBUTE_ADDITIVE : 0))

并且, processhacker提供了现成的定义。对比正常进程创建时调用的NtCreateUserProcess, 最简化情况下我们仅需要:

1
2
#define PS_ATTRIBUTE_IMAGE_INFO \
    PsAttributeValue(PsAttributeImageInfo, FALSE, FALSE, FALSE)

其对应的PS_ATTRIBUTE的字段ValuePtr, 为目标进程的image路径, 和RtlCreateProcessParametersEx中使用的一样。

 

构建好参数后, 我们可以调用NtCreateUserProcess了! 注意, 如果flag设置为线程暂停, 还需要调用NtResumeThread进程才可以正常跑起来。

 

成功调用后, 如上文所述, 可以检查CreateInfostate字段是否为6, 并按照其字段, 输出我们感兴趣的信息。

 

pic5

 

如果你旨在寻找一种手动调用NtCreateUserProcess以创建进程的方法, 成功了, 我们的故事就到此为止了。祝你享受一个美好的周末。

 

不过, 仍有一些奇怪的地方。正如本节一开始所述, NtCreateUserProcess调用后可以视为阶段4的结束, 但NtResumeThread视作阶段6的开始, 中间阶段5的缺失, 会不会导致其他的问题呢。

 

我们创建子进程notepad.exe:

 

pic4

 

噢, "不幸"的事情发生了。

0x02 寻找错误原因

版本差异

我们以notepad.exe为切入点, 尝试找到一种解决方案以正常创建进程。

 

调试方法, 在NtCreateUserProcess调用后, 在NtResumeThread之前, 附加到目标进程。断在LdrIntializeThunk, 由于Parallel Loading技术会断下多次。

 

直接f9跑起来, 发现触发异常:

 

pic5

 

pic6

 

根据日志, 异常发生在comctl32.dll的加载中。查看notepad.exe的导出表,

 

pic7

 

而加载路径中的comctl32.dll, 导出表确实没有序号345 (0x159):

 

pic8

 

与可以正常创建的notepad.exe对比, 正常加载的comctl32.dll存在该导出函数。

 

pic9

 

二者对比, 发现路径上存在差异:

  • 不正常: WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_5.82.19041.1110_none_792d1c772443f647
  • 正常: WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.1110_none_60b5254171f9507e

明显是版本不匹配, 一个5.82一个6.0。推测存在一种机制, 被创建的进程有能力指定加载DLL的版本。而路径中的WinSxS已经提示与SxS重定向机制相关。

Fusion/Sxs redirection

简单来讲, CreateProcessInternalsW在阶段5的工作之一, 先要收集SxS信息, 例如清单文件(Manifest), 之后构建一个包含SxS数据的信息, 发送给Csrss以通知Windows子进程实施SxS重定向机制。有关SxS重定向的原理性描述, 参考Windows Internals 7th, P162。

 

pic10

 

以直观的角度, 查看notepad.exe的清单文件, 显示依赖的comctl32.dll版本为6.0.0.0

 

pic11

 

而默认加载的Windows\System32下的comctl32.dll文件, 版本为5.82:

 

pic12

 

问题的答案呼之欲出, 正是由于阶段5, 缺少通知Windows子系统csrss的信息, 导致SxS重定向机制没有生效。

0x03 通知Windows子系统

CsrClientCallServer 和 BASE_API_MSG

参考Windows Internals 7th, 进程创建流程中的阶段5, 主要实现Windows子系统相关的初始化操作, 分为3个步骤:

  1. client对参数检查并构造信息, 将该信息发送给Windows子系统
  2. Windows子系统(csrss)根据信息判断是否合法, 并实施对应的初始化操作
  3. client后创建阶段, 包含进程参数更新等操作

这3个步骤, 主要围绕Native API: CsrClientCallServer, 以及它的第一个参数, 结构体BASE_API_MSG

 

pic13

 

思路是这样的, 假设CsrClientCallServer是唯一与Windows子系统通信的函数, 那么我们可以认为其参数涵盖了所有进程创建必备的信息。这样, 只要分析出正常进程时其参数各个字段的信息, 我们就有机会自行构造该参数, 自行告知Windows子系统, 使其相信我们是合法的。

 

我参考了以下资料:

  • Geoff Chappel
  • ReactOS
  • leecher1337/ntvdmx64

CsrClientCallServer的函数原型:

1
2
3
4
5
6
7
NTSTATUS
CsrClientCallServer(
    PBASE_API_MSG ApiMessage,
    PVOID CaptureBuffer,
    CSR_API_NUMBER ApiNumber,
    ULONG DataLength
);

而有关BASE_API_MSG结构体的相关信息较为过时, 经过亿点点逆向, 最终可以得出以下结构体:

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
typedef struct {
    BYTE dummy[0x28];
} PORT_MESSAGE;
 
typedef struct _CSR_CAPTURE_HEADER {
    ULONG Length;
    PVOID RelatedCaptureBuffer;         // real: PCSR_CAPTURE_HEADER
    ULONG CountMessagePointers;
    PCHAR FreeSpace;
    ULONG_PTR MessagePointerOffsets[1]; // Offsets within CSR_API_MSG of pointers
} CSR_CAPTURE_HEADER, * PCSR_CAPTURE_HEADER;
 
typedef ULONG CSR_API_NUMBER;
 
////////////////////////////////////////////////////////////////////////////////////////////////////
 
typedef struct
{
    ULONG_PTR UniqueProcess;
    ULONG_PTR UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
 
__declspec(align(8))
typedef struct
{
    BYTE byte0;                        // +00       
    BYTE byte1;                        // +01
    BYTE byte2;                        // +02
    BYTE byte3;                        // +02
    ULONG64 DUMMY;                    // +08       
    ULONG_PTR ManifestAddress;        // +10       
    ULONG64 ManifestSize;            // +18       
    HANDLE SectionHandle;            // +20
    ULONG64 Offset;                    // +28
    ULONG_PTR Size;                    // +30
} BASE_SXS_STREAM;                    // 0x38
 
typedef struct
{
    ULONG Flags;                    // +00     
    ULONG ProcessParameterFlags;    // +04     
    HANDLE FileHandle;                // +08     
    UNICODE_STRING FileName1;        // +10     
    UNICODE_STRING FileName2;        // +20     
    BYTE    Field30[0x10];          // +30     
    BASE_SXS_STREAM PolicyStream;    // +40     
    UNICODE_STRING AssemblyName;    // +78     
    UNICODE_STRING FileName3;        // +88     
    BYTE    Field98[0x10];            // +98     
    UNICODE_STRING FileName4;        // +a8     
    BYTE OtherFileds[0x110];        // +b8       
} BASE_SXS_CREATEPROCESS_MSG;        // 0x1C8
 
__declspec(align(8))
typedef struct {
    HANDLE ProcessHandle;            // +00     
    HANDLE ThreadHandle;            // +08     
    CLIENT_ID ClientId;                // +10     
    ULONG CreationFlags;            // +20     
    ULONG VdmBinaryType;            // +24     
    ULONG VdmTask;                    // +28     
    HANDLE hVDM;                    // +30     
    BASE_SXS_CREATEPROCESS_MSG Sxs;    // +38     
    ULONG64 PebAddressNative;       // +200    
    ULONG_PTR PebAddressWow64;        // +208    
    USHORT ProcessorArchitecture;    // +210    
} BASE_CREATEPROCESS_MSG;
 
////////////////////////////////////////////////////////////////////////////////////////////////////
 
__declspec(align(8))
typedef struct {
    PORT_MESSAGE h;
    PCSR_CAPTURE_HEADER CaptureBuffer;            // 0x28
    CSR_API_NUMBER ApiNumber;                    // 0x30
    ULONG ReturnValue;                            // 0x34
    ULONG64 Reserved;                            // 0x38
    BASE_CREATEPROCESS_MSG CreateProcessMSG;    // 0x40
} BASE_API_MSG, *PBASE_API_MSG;

伪造这样的结构体难以第一次就成功, 如果调用错误只有CsrClientCallServer的NTSTATUS返回值能提供信息。为此还需要了解与Windows子系统的通信的基础概念与机制。

InternalSxsCreateProcess

CsrClientCallServer本质上使用ALPC进行通信,

 

pic14

 

在alpc通信模型中, 具有客户端(client)和服务端(server)。

 

pic15

 

利用windbg的!alpc命令, 结合PortAddress或结合EPROCESS得到详细信息。调试下, 我们可以确认父进程确实与csrss.exe进行通信。

 

但依然不知道扔进去的数据, csrss是如何处理的。参考一些公开资料, 可以了解到csrss由csrsrv.dll实现本体功能, 并由另外3个dll负责具体功能:

  • basesrv.dll
  • sxssrv.dll
  • winsrv.dll

这三个都简单看下, 发现令人感兴趣的函数名

  • csrsrv!CsrApiRequestThread
  • basesrv!BaseSrvCreateProcess2

对csrss.exe进行内核态下的调试, 控制alpc的调用, 我们可以得到以下执行逻辑:

 

pic_alpc

 

sxssrv!InternalSxsCreateProcess实现了与Windows子系统相关的进程创建的具体逻辑。

 

这样, 当调用CsrClientCallServer失败时, 我们有了可以优先考虑并分析的函数。

最后的N步

回到notepad.exe的345错误。先调试正常创建的notepad.exe, 在LdrInitializeThunk断下, 此时PEB.ActivationContextData字段已经有值了, 说明该字段由父进程创建有关。将该字段置0, F9, 会出现STATUS_ORDINAL_NOT_FOUND一样的报错。

 

我们可以推测该字段的缺失正是SxS机制没有起作用的表现。所以, 只要我们找到正常创建进程下, 何时子进程的PEB中诞生了该字段的值, 就能找到根本原因。

 

仍然需要通过对正常进程创建时的BASE_API_MSG分析。

 

注意到在BASE_SXS_STREAM的偏移+0x10和偏移+0x18处有值, 而在伪造的BASE_API_MSG中为空。

 

pic16

 

有趣的是, 偏移+0x10上的值看起来是个地址, 但却不能follow。那么如果不是父进程, 只有一种可能性, 就是子进程的。此时子进程已经被NtCreateUserProcess调用后被创建, 所以可以查看其内存布局:

 

pic17

 

而这正是notepad.exe的Manifest文件的数据, 偏移+0x18即为Manifest文件的长度。

 

于是, 将PS_CREATE_INFO.SuccessState后返回的结果, 复制给CreateProcessMSG.Sxs:

1
2
m.CreateProcessMSG.Sxs.PolicyStream.ManifestAddress = createInfo.SuccessState.ManifestAddress;
m.CreateProcessMSG.Sxs.PolicyStream.ManifestSize = createInfo.SuccessState.ManifestSize;

之后, 如果调用CsrClientCallServer返回STATUS_ACCESS_DENIED。欢迎来到最后一步!

 

正如上一小节所述, 优先分析InternalSxsCreateProcess何处抛出的STATUS_ACCESS_DENIED:

 

pic18

 

与正常情况对比:

 

pic19

 

异常情况:

 

pic20

 

发现没有读权限, 自然无法读子进程, 产生访问拒绝也不奇怪了。

 

往上溯源, 最终发现句柄在nt!NtCreateUserProcess中被创建:

 

pic21

 

createProcCtx作为PspCaptureCreateInfo的返回值:

 

pic22

 

而默认情况下, 会or 0x100020, 代表Sync | Execute/Traverse

 

所以, 我们需要在NtCreateUserProcessCreateInfo参数中, 添加AdditionalFileAccess:

1
createInfo.InitState.AdditionalFileAccess = 0x1000a1; // Synch | Read/List | Execute/Traverse | ReadAttr (used by SxS)

至此, 所需的皆以满足:

 

pic23

 

正常创建notepad.exe成功!

 

完整的项目地址: Direct-NtCreateUserProcess

0x04 Epilogue

本文至此就要结束了。NtCreateUserProcess之前存在公开代码(Microwave89), 可惜无法正常工作, 但是作者提供了一种可行的蓝图。本项目中进程创建过程中的API皆为Native API, 理论上下一步可以全部使用Syswhisper3等Direct Syscall技术以实现Bypass AV/EDR。
另外, BASE_API_MSG对于红队来讲, 似乎还有可挖掘的空间, 期待后续对此的研究。

 

参考文章以及代码:

  • Windows Internals 7th
  • Geoff Chappel
  • ReactOS
  • processhacker
  • leecher1337/ntvdmx64

[培训]《安卓高级研修班(网课)》月薪三万计划

最后于 2022-5-16 08:44 被D0pam1ne编辑 ,原因:
收藏
点赞15
打赏
分享
最新回复 (17)
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
zz77 2022-5-17 10:55
2
0
大赞。这几天扒拉XP源码没搞定CSR,你这个简洁明了。有点小建议,
既然是NativeAPI程序,应避免调用kernel32函数,可稍微调整一下,比如
m.CreateProcessMSG.ClientId.UniqueProcess = pClientId->UniqueProcess; //::GetProcessId(hProcess);
m.CreateProcessMSG.ClientId.UniqueThread = pClientId->UniqueThread; //::GetThreadId(hThread);

GetLastError可以用ntdll的RtlGetLastWin32Error,或者NtCurrentTeb()->LastErrorValue
雪    币: 1060
活跃值: (280)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
D0pam1ne 1 2022-5-17 11:50
3
0
zz77 大赞。这几天扒拉XP源码没搞定CSR,你这个简洁明了。有点小建议, 既然是NativeAPI程序,应避免调用kernel32函数,可稍微调整一下,比如 m.CreateProcessMSG.Cli ...
非常感谢! 这部分旨在输出信息而考虑不周了
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
zz77 2022-5-17 12:49
4
0
另外Nt函数出现错误时不会设置LastStatusValue和LastErrorValue,这时GetLastError得不到错误信息,还是需要根据返回的NTSTATUS来解释。
雪    币: 89
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_voklbwsn 2022-5-17 13:04
5
0
难受啊,我四月份就弄好了,在做兼容适配,被大佬先发布了
雪    币: 576
活跃值: (2035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kakasasa 2022-5-17 15:19
6
0
mark一下 
雪    币: 1060
活跃值: (280)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
D0pam1ne 1 2022-5-17 21:19
7
0
zz77 另外Nt函数出现错误时不会设置LastStatusValue和LastErrorValue,这时GetLastError得不到错误信息,还是需要根据返回的NTSTATUS来解释。
确实. 代码已更新.
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
ntd11 2022-5-18 08:24
8
0
[+] Process Handle                 = 0x00000000000000BC
[+] Thread Handle                  = 0x00000000000000B4
[+] target process pid             = 0x27d0
[+] target thread pid              = 0x149c
[+] createInfo.State               = 0x6
[+] createInfo.FileHandle          = 0x00000000000000C0
[+] createInfo.SectionHandle       = 0x00000000000000CC
[+] createInfo.PebAddressNative    = 0xf49000
[+] createInfo.ManifestAddress     = 0x7ff7160c78b0
[+] createInfo.ManifestSize        = 0x270
[>] peb                            = 0x0000000000F49000
[+] capture success!               = 0x0000000000010750
[-] CsrClientCallServer failed     = 0xC000002F              ??????????????????????????
[>] done!
雪    币: 5228
活跃值: (11659)
能力值: ( LV12,RANK:312 )
在线值:
发帖
回帖
粉丝
一半人生 5 2022-5-18 08:54
9
0
幸苦
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
ntd11 2022-5-18 09:09
10
0
通知那里不稳妥,是否可以考虑csrsrv!CsrCreateProcess
雪    币: 1060
活跃值: (280)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
D0pam1ne 1 2022-5-18 09:14
11
0
ntd11 通知那里不稳妥,是否可以考虑csrsrv!CsrCreateProcess
问题多半出在不同os版本导致的BASE_API_MSG不同。使用CsrClientCallServer的原因为它是native api。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
ntd11 2022-5-18 09:37
12
0
那这个就只是理论了,应用不了实践,后续工作很多,或者说,刚进入角色,还是考虑下稳妥方案
雪    币: 3418
活跃值: (3627)
能力值: ( LV8,RANK:131 )
在线值:
发帖
回帖
粉丝
coneco 2 2022-5-18 09:46
13
0
感谢分享
雪    币: 1060
活跃值: (280)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
D0pam1ne 1 2022-5-18 10:56
14
0
ntd11 那这个就只是理论了,应用不了实践,后续工作很多,或者说,刚进入角色,还是考虑下稳妥方案
本项目提供PoC, 而非解决方案(将来没有计划)。如果你所创建的进程不依赖SxS机制, 可以将宏IS_NOT_MINIMAL注释, 忽略与csrss通信。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
ntd11 2022-5-18 11:11
15
0
感谢分享
雪    币: 19
活跃值: (272)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小朋友呢 2022-6-1 11:16
16
0
感谢大佬的分享,有一个问题,在执行像是有回显命令的时候,这时需要自己创建一个管道来读取数据,但是在读取的时候会一直处于阻塞状态
雪    币: 1060
活跃值: (280)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
D0pam1ne 1 2022-6-6 00:09
17
0
小朋友呢 感谢大佬的分享,有一个问题,在执行像是有回显命令的时候,这时需要自己创建一个管道来读取数据,但是在读取的时候会一直处于阻塞状态
这是我没有遇到的情况, 可以私信我吗?
雪    币: 811
活跃值: (1190)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Hbruce 2022-6-17 16:35
18
0
用这个启动steam进程信息都成功了,但是进程自动退出了。。
游客
登录 | 注册 方可回帖
返回