找回密码
 加入计匠网
搜索
热搜: BIOS ACPI CPU Windows
查看: 10705|回复: 1

以system权限启动应用程序

[复制链接]
发表于 2011-8-5 21:27:34 | 显示全部楼层 |阅读模式
最近在搞一个项目,需要程序开机自动运行,可是程序中调用了底层驱动的一些函数,必须以管理员的权限才能运行,否则程序运行不成功,在XP 下 直接写注册表就可以,可是在VISTA 和 WIN7 下写注册表的方式失效,因为必须以管理员的权限运行才可以,迫于无奈,上网查了N多资料,终于找到了一种解决的办法,在此分享出来,以此献给被此问题苦恼的人!
: j0 |6 B* Y6 L4 f1 \* r# M0 I4 a( j* _# n% _
首先介绍一下,解决问题的思路,创建一个服务,安装在系统中,在服务里以SYSTEM 的权限创建一个进程,用来启动自己的应用程序,我们想什么时候启动我们的应用程序,只需要我们用应用程序给服务发送一个信号,在服务接收到信号后,就可以启动我们想要运行的应用程序了。! [# b8 h- Z$ ~, f
0 F/ ]9 Q0 i* E0 M$ h4 j0 C) @
实现框架如下:8 q2 q9 M) g! R
6 a% ?- n' g6 R, z0 v

' b( \$ V% b" b! s- H/ r  ?
" ^" s. _, N2 K% j, }所以在这里我们需要创建三个程序:1.Windows 服务程序 2.我们自己的应用程序 3.给服务发送信号的应用程序。* F/ ?4 M* F9 y; \7 F2 e5 n  @
2 k1 F- f  V& {" w
当然其中的 1和3 可以合并在一起,而且 2  我们可以做成多个应用程序。这样只要是我们自己写的都可以以SYSTEM的权限运行了,比管理员更实用。这里需要注意的是第一次安装服务的时候必须以管理员的权限运行。
4 ]6 R4 h* y2 h0 `- s# [9 y6 b3 x( y+ m+ S3 ^* j8 X% I3 Z9 n: H
好了,闲话少说,下面步入正题,我做了个简单的Demo,是以服务的方式启动系统自带的管理记事本程序(windows 7下面的,用VS2008编辑)。
0 h  Z" T8 v, {3 g
- |) D3 |# q, [/ O我们以函数CreateProcessAsUser 来开始讲解,我们所要做的动作就是把这个函数的各个参数都填对 就OK,只需把其中的几个关键参数填好,其他设置为NULL 就OK ,
# ]" r. _% ~3 M+ ^7 R, f+ u+ b+ y- E, Y
首先第一个参数HANDLE hToken ,Token 句柄,怎么得到这个句柄,MSDN 给出了两种办法,一种通过调用 LogonUser函数 ,一种另外一种通过 调用DuplicateTokenEx 函数,在这里我们选择第二种方式创建一个模拟的Token,关键是这个模拟的Token那里来,那我们就得追踪DuplicateTokenEx里面的各个参数,其中DuplicateTokenEx参数如下:$ e2 @2 U# N4 ?4 Y: c" g1 o
* @- y1 T* o7 R* F
BOOL WINAPI DuplicateTokenEx(: O+ S) o6 l6 b4 W: i6 G
  __in          HANDLE hExistingToken,+ U9 s- A# u+ l% V0 b$ Y. l3 b
  __in          DWORD dwDesiredAccess,- z# e2 ^5 A& X1 U7 V+ Z
  __in_opt      LPSECURITY_ATTRIBUTES lpTokenAttributes,
! w' w5 G2 N% e" k1 {/ U  __in          SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,5 h) F, L, E+ d
  __in          TOKEN_TYPE TokenType," `5 K# {$ @1 o! {
  __out         PHANDLE phNewToken- c! H5 o% Y( ~4 e
);
+ L0 \5 L: j: U/ B这个函数的主要功能就是根据现有的Token 来创建一个新的Token,我们需要的就是这个新的Token,如何得到这个新的Token,看来我们还得往下追踪哦,第二个参数是新建Token的权限,这个参数直接设置成MAXIMUM_ALLOWED就可以,第三个参数是 安全描述符的指针,这里直接设置成NULL,分配成一个默认的安全描述符,第四个参数设置成SecurityIdentification  的OK,(安全描述符的级别)  第五个参数 Token类型 直接设置成TokenPrimary OK  因为它就是用于CreateProcessAsUser的函数的。最后一个参数就是我们想要的参数了。我们主要就是得到他,要想得到这个参数 我们必须得到第一个参数。9 ]3 G/ k4 g8 K9 m+ G2 {
9 y1 x( o) o, ]3 M  H4 f( P
第一个参数是一个已经存在的Token,数要想得到这个Token,必须找到以个进程,把这个进程的Token 拿过来为我们所用,得到这个Token 要运行函数OpenPrcessToken通过这个函数得到Token的句柄,但是要得到这个Token的句柄,必须要通过函数OpenProcess得到进程的句柄,要得到进程的句柄 必须通过函数ProcessIdToSessionId得到进程的ID。因为我们系统每次登入的时候都有一个winlogon.exe,我们就拿这个进程的ID 来得到CreateProcessAsUser函数的第一个参数。也就是把上面的一步步还原回去!+ R8 n& C# d7 m) o" G% y

& r3 V$ A' h! c- `5 a. T6 S- u5 t3 z$ J
; g- K! q3 I1 J/ S) A. H5 }
( T4 J, N+ g& C! _# g- u. F/ pdwSessionId = WTSGetActiveConsoleSessionId(); //得到当前用户的会话ID                 //////////////////////////////////////////
/ I; _3 r. J- _- h% M8 q- Z/ I( I// Find the winlogon process
6 c( l, L4 i% Y& C1 d. `( r0 S5 z///////////////////////////////////////// k/ g6 g3 }; V; Z
PROCESSENTRY32 procEntry;  //用来存放快照进程信息的一个结构体
- d) u# i# l7 n  b//函数为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程[THREAD])建立一个快照[snapshot]
; s2 [( z* s  a4 w: n% P1 W* Y8 y     HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
$ E9 E2 ^8 J9 J( i4 {6 N* m     if (hSnap == INVALID_HANDLE_VALUE)
+ I! a* ^4 ^6 J         {
1 j0 r/ p: Y" G                 return 1 ;
, x  G( \: Q! }+ r         }
3 L! j/ D& e. S9 r! x' R8 A' Z         procEntry.dwSize = sizeof(PROCESSENTRY32);! z+ h% h+ Z" P# S) T5 r8 k
         if (!Process32First(hSnap, &procEntry)) //获得第一个进程的句柄.+ m) g  P  C4 o: U
         {
: w' \! Y: b$ c                 return 1 ;/ S. M* G# |2 ~' H1 m. H
         }
8 I4 }" {! E& D2 a! G2 y* h         do$ w9 }! {" Y1 M4 G
         {
9 q5 l' O1 c4 X: Y( N$ fif (_wcsicmp(procEntry.szExeFile, _T("winlogon.exe")) == 0)  //查找winlogon.exe0 Z0 |0 k1 i2 S; I* }: H# X
         {
8 t+ y, \! N* L) [         // We found a winlogon process...make sure it's running in the console session
+ }. e# W0 V. d' f         DWORD winlogonSessId = 0;
, o! \9 k+ `* N$ u3 Z4 l9 n8 a0 J        if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId)//得到与进程ID对应的终端服务会话ID
# y7 L) `" ?; [0 \6 U                          {
7 F) _2 g4 _6 k' C7 H, n% h/ _                                   winlogonPid = procEntry.th32ProcessID;
- S% K$ H4 V6 m/ f, i6 l                                   break;2 `4 {1 ^) o' C- l, `6 |( M- [
                          }
9 X* I" P, N) U7 M  J1 o                 }- [1 V; h* i  v; J
         } while (Process32Next(hSnap, &procEntry)); //获得下一个进程的句柄
9 ?* O* k1 c8 L: P7 F         ////////////////////////////////////////////////////////////////////////
: a3 |7 N  m5 k' m' [  H         hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);  //获得进程句柄
: e9 z7 c. ^* k3 {) O& L         if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY0 k* ~% `) W6 @1 m, q: g
                 |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID+ \3 \: |9 ^/ y4 I+ v6 B2 \/ p
                 |TOKEN_READ|TOKEN_WRITE,&hPToken))                //获得令牌句柄
. Z1 p) M, n' o/ X         {" J2 G4 L0 X7 q
                 int abcd = GetLastError();
% D7 B' g: m- m$ t                 printf("Process token open Error: %u\n",GetLastError());5 `9 G8 I9 v$ b
         }
* h$ K. ?, V4 I1 M       DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);//创建模拟令牌  a  O& ?* z' ]
         int dup = GetLastError();
$ H/ b8 g, ]- @7 Z通过上面的函数我们得到了这个DuplicateTokenEx函数的最后一个参数后,我们还不能直接用,根据MSDN 的说法要用SetTokenInformation来设置一下( T* }% a4 ]' x# F

( i$ l8 c" |* s, bBOOL WINAPI SetTokenInformation(
" h$ `: h% e+ n: ?  __in          HANDLE TokenHandle,2 {5 v( d# Q, o* f3 ^1 B
  __in          TOKEN_INFORMATION_CLASS TokenInformationClass,
5 u8 ?6 [0 [. j  G/ T  __in          LPVOID TokenInformation,
- W  O$ Q( {+ N  __in          DWORD TokenInformationLength
% o6 J: h3 y$ |3 F);1 l: ^! @2 P! d1 R6 {
其中第一个参数就是我们得到Toke 的句柄,第二个参数会话ID ,也就是把会话ID 设置到备份令牌中,代码如下:
5 T! [9 f0 e8 O" z) f* a. o1 f
5 |# j' l' P$ r- H- K! m: R+ H/ OSetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD))/ t+ J" `, w& U1 L
设置完成后 最好检验一下,当然不检验也没有关系了,代码如下:4 s1 `. o) K: m* u

3 E# t& X! x/ d' n  if(!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL)) //这个函数启用或禁止指定访问令牌的特权
7 x8 b$ _# I+ b1 G( ~$ O" J         {               
) T0 I: r9 |9 `! |9 o                 int abc =GetLastError();
+ I8 V7 x$ o# r* d3 a. m: R( t                 printf("Adjust Privilege value Error: %u\n",GetLastError());, x" @+ k" w8 V1 N9 P  c7 k. h( q
         }3 v1 C8 V0 X+ \
         if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)& N) b9 W7 A* O2 i8 V; [& }
         {4 U* Z; g* b$ A7 t6 g! ]9 n$ W
                 printf("Token does not have the provilege\n");8 D5 r% L3 G2 x% I1 U; k6 e
         }; q, b" k0 Y2 `  \8 b6 H

% ]* K) Y1 ~* C4 u  K  i1 J这样的话CreateProcessAsUser第一个参数的工作算是正式完成,下面几个参数就简单了,, V, W: Y  K( _9 \

' y9 _1 ~( u0 K; O0 r1 Y大家直接看代码吧. K! m7 s4 H- D

4 Q& o1 A2 y; K7 s( h         bResult = CreateProcessAsUser(7 U( v4 Z; l8 z
                 hUserTokenDup,                              // 这个参数上面已经得到0 q- s  s: M' ^: F
                 _T("C:\\Windows\\System32\\notepad.exe"), //执行文件的路径0 C" z0 C: c3 R. [. Y) G
                 NULL,                              // command line
9 k1 n( z  o: S3 _( q                 NULL,              // pointer to process SECURITY_ATTRIBUTES
1 \  n- _3 D! P$ b3 Y# }- }                 NULL,              // pointer to thread SECURITY_ATTRIBUTES, h8 Z  V2 I# D6 k
                 FALSE,             // handles are not inheritable8 [6 B9 C* [$ m, ~$ a0 A
                 dwCreationFlags, // creation flags: V! P1 C8 n6 o
                 pEnv,              // pointer to new environment block+ r3 j: M5 b) m1 T# z  ~1 r) t: V: b
                 NULL,              // name of current directory
* \* o1 B" U6 V3 j: ^                 &si,               // pointer to STARTUPINFO structure
( n. Q- U! b6 U( |                 &pi                // receives information about new process
; g7 n. j9 n$ }, F# \. q                 );
9 M' ?* g; B1 n- Q- X. A' s4 T : P/ v3 r* l. l; f

( U; R" `4 M: y) y3 [最后大家别忘了把打开的句柄关闭。这样看起来是不是就有点简单了,其实也没什么,剩下的就是Winodws 服务的基本框架的一些东西,那些就简单了。 以上都是自己根据MSDN理解得来的,如有什么问题欢迎大家指正!
0 X: |' I. G( g5 R7 {; d6 g# W0 [; q' N' A0 f4 y* s5 M
附上Demo下载地址:http://download.csdn.net/source/3497793
发表于 2011-8-8 16:28:59 | 显示全部楼层
不錯。。。我前兩個月給OEM做的出貨用的GSensor Protect AP就是這個做法
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入计匠网

本版积分规则

Archiver|手机版|小黑屋|计匠网

GMT+8, 2026-11-1 20:32 , Processed in 4.089952 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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