# NetUserAdd逆向

## 起因

![](/files/-MU9Iv8D4FwsAYblR1Zb)

## 过程

反手直接拖ida。

![](/files/-MU9KGDxaWs9fJL500Dc)

![](/files/-MU9KWKSKfndke5fhqVB)

跟了下逻辑然后对比了下React OS发现逻辑几乎一致，那直接扣代码。

![](/files/-MU9L6Slg0OQrvfA0dVg)

win10上UaspOpenDomain没有导出，可以使用特征码搜索的方式去调用，这里跟进了发现同样是调用了sam系函数。

![](/files/-MU9LSYIKF_XhjCiBX30)

跟一下函数还需要sid。

![](/files/-MU9M4-oywKHqFh4zigW)

![](/files/-MU9MAGjGPrxFByt90fJ)

发现是由 LsaQueryInformationPolicy的获取，这个函数在ntsecapi.h里有描述，直接拿来用就好了。

至此用户创建完成，然后通过SetUserInfo设置密码，同样这个函数在windows 10上没有导出。

![](/files/-MU9MeyqIOU3yMk3JoUo)

![](/files/-MU9MqPILkHQdprNfYNd)

跟一下，发现下层函数一致并导出。

![](/files/-MU9N2teBH84UP6hN7dl)

![](/files/-MU9N9D8gfZ60EhPp2Rc)

![](/files/-MU9NEw4oxNTaQhSzC7m)

跟踪了一下函数逻辑，发现不同的UserInfo都有不同的处理方法，通常我们会传入一个USERINFO1结构体，这里会把有效信息传入到一个 USER\_ALL\_INFORMATION 结构体里面，这个结构体的实现和Startupinfo有点像，需要同时设置值和使用标签位，阅读发现，有一个结构体单处理密码。

![](/files/-MU9OL9sK7eqjtyN3vM5)

![](/files/-MU9OTeKHHwEoU2v2gFa)

这里我们只需要传入密码，然后将标志位设1。

我们就自己封装出了一个NetUserAdd。

## 完整代码

```
#include "ApiAddUser.h"



int wmain(int argc, wchar_t* argv[])
{
	UNICODE_STRING UserName;
	UNICODE_STRING PassWord;
	HANDLE ServerHandle = NULL;
	HANDLE DomainHandle = NULL;
	HANDLE UserHandle = NULL;
	ULONG GrantedAccess;
	ULONG RelativeId;
	NTSTATUS Status = NULL;
	HMODULE hSamlib = NULL;
	HMODULE hNtdll = NULL;
	HMODULE hNetapi32 = NULL;
	LSA_HANDLE hPolicy = NULL;
	LSA_OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
	PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
	USER_ALL_INFORMATION uai = { 0 };


	hSamlib = LoadLibraryA("samlib.dll");
	hNtdll = LoadLibraryA("ntdll");

	pSamConnect SamConnect = (pSamConnect)GetProcAddress(hSamlib, "SamConnect");
	pSamOpenDomain SamOpenDomain = (pSamOpenDomain)GetProcAddress(hSamlib, "SamOpenDomain");
	pSamCreateUser2InDomain SamCreateUser2InDomain = (pSamCreateUser2InDomain)GetProcAddress(hSamlib, "SamCreateUser2InDomain");
	pSamSetInformationUser SamSetInformationUser = (pSamSetInformationUser)GetProcAddress(hSamlib, "SamSetInformationUser");
	pSamQuerySecurityObject SamQuerySecurityObject = (pSamQuerySecurityObject)GetProcAddress(hSamlib, "SamQuerySecurityObject");
	pRtlInitUnicodeString RtlInitUnicodeString = (pRtlInitUnicodeString)GetProcAddress(hNtdll, "RtlInitUnicodeString");

	RtlInitUnicodeString(&UserName, L"Admin");
	RtlInitUnicodeString(&PassWord, L"Admin");

	Status = SamConnect(NULL, &ServerHandle, SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN, NULL);;
	Status = LsaOpenPolicy(NULL,&ObjectAttributes,POLICY_VIEW_LOCAL_INFORMATION,&hPolicy);
	Status = LsaQueryInformationPolicy(hPolicy, PolicyAccountDomainInformation, (PVOID*)&DomainInfo);

	Status = SamOpenDomain(ServerHandle, 
		DOMAIN_CREATE_USER | DOMAIN_LOOKUP | DOMAIN_READ_PASSWORD_PARAMETERS, 
		DomainInfo->DomainSid, 
		&DomainHandle);

	Status = SamCreateUser2InDomain(DomainHandle,
		&UserName,
		USER_NORMAL_ACCOUNT,
		USER_ALL_ACCESS | DELETE | WRITE_DAC,
		&UserHandle,&GrantedAccess,&RelativeId);

	RtlInitUnicodeString(&uai.NtPassword, PassWord.Buffer);
	uai.NtPasswordPresent = TRUE;
	uai.WhichFields |= USER_ALL_NTPASSWORDPRESENT;


	Status = SamSetInformationUser(UserHandle,
		UserAllInformation,
		&uai);

	return 0;
}
```

## LINKS

{% embed url="<https://doxygen.reactos.org/d2/d5b/dll_2win32_2netapi32_2user_8c.html#a854f5ebc802849632ccda207250e7b04>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://idiotc4t.com/redteam-research/netuseradd-ni-xiang.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
