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

以system权限启动应用程序

[复制链接]
发表于 2011-8-5 21:27:34 | 显示全部楼层 |阅读模式
最近在搞一个项目,需要程序开机自动运行,可是程序中调用了底层驱动的一些函数,必须以管理员的权限才能运行,否则程序运行不成功,在XP 下 直接写注册表就可以,可是在VISTA 和 WIN7 下写注册表的方式失效,因为必须以管理员的权限运行才可以,迫于无奈,上网查了N多资料,终于找到了一种解决的办法,在此分享出来,以此献给被此问题苦恼的人!
3 A8 S9 V+ O2 ]2 Y9 e: p# f+ L6 S2 V1 E+ |1 D3 d
首先介绍一下,解决问题的思路,创建一个服务,安装在系统中,在服务里以SYSTEM 的权限创建一个进程,用来启动自己的应用程序,我们想什么时候启动我们的应用程序,只需要我们用应用程序给服务发送一个信号,在服务接收到信号后,就可以启动我们想要运行的应用程序了。
; v  z* v' w6 w  V8 h2 a/ D2 z
- Z, ~! G9 d* @( r% q- ?- D实现框架如下:
+ C' `9 C. n& f; A6 l
1 ~1 c" H6 Q! e$ f$ _ ) F) V3 V/ ]- E- }( w; O) e7 V6 o& Q7 g

# y5 N' S! k; h1 ~% W. [' {2 s1 Y所以在这里我们需要创建三个程序:1.Windows 服务程序 2.我们自己的应用程序 3.给服务发送信号的应用程序。
! o* c/ g( i# b8 d- u* _
' ?0 J* U# G( f8 a9 ?当然其中的 1和3 可以合并在一起,而且 2  我们可以做成多个应用程序。这样只要是我们自己写的都可以以SYSTEM的权限运行了,比管理员更实用。这里需要注意的是第一次安装服务的时候必须以管理员的权限运行。0 _& H& ]( Z; S# s

! s! ^% Q* ~- d% ^! w好了,闲话少说,下面步入正题,我做了个简单的Demo,是以服务的方式启动系统自带的管理记事本程序(windows 7下面的,用VS2008编辑)。
! O7 U  n: `% a& F6 ], a* C: w
8 ?* j2 n! Z9 @! X0 K5 ~/ i. r我们以函数CreateProcessAsUser 来开始讲解,我们所要做的动作就是把这个函数的各个参数都填对 就OK,只需把其中的几个关键参数填好,其他设置为NULL 就OK ,& s1 m& t. c, H' }* L' T0 ]
" W. E+ m+ ]- K) D; b3 F" `' M8 b
首先第一个参数HANDLE hToken ,Token 句柄,怎么得到这个句柄,MSDN 给出了两种办法,一种通过调用 LogonUser函数 ,一种另外一种通过 调用DuplicateTokenEx 函数,在这里我们选择第二种方式创建一个模拟的Token,关键是这个模拟的Token那里来,那我们就得追踪DuplicateTokenEx里面的各个参数,其中DuplicateTokenEx参数如下:
6 \0 I5 k5 g; k4 {% I0 A7 o8 G' \; N
BOOL WINAPI DuplicateTokenEx(
* ^9 ~9 w( j" g& o9 Y  __in          HANDLE hExistingToken,) x) n5 y2 K* p0 u, F2 [9 a5 f
  __in          DWORD dwDesiredAccess,
; a, o- t0 ^0 c* y; H  __in_opt      LPSECURITY_ATTRIBUTES lpTokenAttributes,1 Q, F" U+ n& f
  __in          SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,* i6 ^! e' w  G" D- _
  __in          TOKEN_TYPE TokenType,
4 N* c: d$ W. I8 k; I  __out         PHANDLE phNewToken
# B0 @" u- V5 z. v8 Y8 R. X# L);' z5 d" c! r! M" A
这个函数的主要功能就是根据现有的Token 来创建一个新的Token,我们需要的就是这个新的Token,如何得到这个新的Token,看来我们还得往下追踪哦,第二个参数是新建Token的权限,这个参数直接设置成MAXIMUM_ALLOWED就可以,第三个参数是 安全描述符的指针,这里直接设置成NULL,分配成一个默认的安全描述符,第四个参数设置成SecurityIdentification  的OK,(安全描述符的级别)  第五个参数 Token类型 直接设置成TokenPrimary OK  因为它就是用于CreateProcessAsUser的函数的。最后一个参数就是我们想要的参数了。我们主要就是得到他,要想得到这个参数 我们必须得到第一个参数。# S: O: T8 X$ U) }

, t2 H& `/ L& k/ g第一个参数是一个已经存在的Token,数要想得到这个Token,必须找到以个进程,把这个进程的Token 拿过来为我们所用,得到这个Token 要运行函数OpenPrcessToken通过这个函数得到Token的句柄,但是要得到这个Token的句柄,必须要通过函数OpenProcess得到进程的句柄,要得到进程的句柄 必须通过函数ProcessIdToSessionId得到进程的ID。因为我们系统每次登入的时候都有一个winlogon.exe,我们就拿这个进程的ID 来得到CreateProcessAsUser函数的第一个参数。也就是把上面的一步步还原回去!7 P; T+ u5 z8 O+ `2 b- I

) ]/ o' d& l; c% ?% {6 J4 V 1 x/ y& N) K. t# c" [
# E/ f8 O& V' W3 M7 d
dwSessionId = WTSGetActiveConsoleSessionId(); //得到当前用户的会话ID                 //////////////////////////////////////////4 Y. w7 K* I+ A. l0 y
// Find the winlogon process
' K( I& K. o5 h5 K////////////////////////////////////////
8 X8 J2 u  c/ v* D- x$ @PROCESSENTRY32 procEntry;  //用来存放快照进程信息的一个结构体
: ?) L% I+ T* q! @, P, a* a//函数为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程[THREAD])建立一个快照[snapshot]
; z, j1 d9 C+ _8 K8 L9 i- }2 @     HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);9 u, P% `& C6 k3 h# k. m
     if (hSnap == INVALID_HANDLE_VALUE)
5 ?) U' g6 C4 d6 y/ \  _8 H! j4 ?! B         {- ?$ I) h/ F- A% f
                 return 1 ;- i) L+ B, |0 t4 u3 Z( v! d- ?) b
         }
! D& O& ~! |4 S6 ]. Z         procEntry.dwSize = sizeof(PROCESSENTRY32);
7 v: ~8 R* q* R3 x         if (!Process32First(hSnap, &procEntry)) //获得第一个进程的句柄.
3 J" v* p1 X4 V% q9 k         {
4 x5 i1 h' K- Y) V$ N4 @                 return 1 ;0 s' s( a: I( _. u9 U6 `( m
         }4 R% z0 g# d  v( c" L1 g' R7 D
         do
3 G+ g2 h" J$ W% ~6 q! v4 E/ N         {6 [1 m- e% u4 w" p7 L* k. S/ {
if (_wcsicmp(procEntry.szExeFile, _T("winlogon.exe")) == 0)  //查找winlogon.exe
+ i# Z+ y1 P  y9 Y, v  l% B         {) E1 `+ ^5 U+ d) ~- \% @/ S
         // We found a winlogon process...make sure it's running in the console session$ K) e# K3 A3 N9 o( G* d
         DWORD winlogonSessId = 0;, W8 T; w; r5 w2 X7 l+ V
        if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId)//得到与进程ID对应的终端服务会话ID: c% L6 d4 K5 b
                          {- D" t4 k' K' S4 q
                                   winlogonPid = procEntry.th32ProcessID;3 S% W# u& n6 T. x: j0 W1 @
                                   break;
0 G' H- Z  ^3 h3 @; R8 y                          }# K  e) p8 _  E2 p6 ?7 @; [' z6 A8 O+ h
                 }
6 j4 Y0 f; i) F         } while (Process32Next(hSnap, &procEntry)); //获得下一个进程的句柄6 `' H) X" B3 s4 X/ [# D
         ////////////////////////////////////////////////////////////////////////  Z/ a2 Z* m* |' c1 X* L6 r
         hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);  //获得进程句柄5 }6 c" Z% F2 N& e, Q3 Z- w3 {
         if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY+ I% K/ I% Q. \4 a, |0 C: A
                 |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID
- l* T! f) K. I$ R4 k6 m: X                 |TOKEN_READ|TOKEN_WRITE,&hPToken))                //获得令牌句柄5 t; A) D% W# @& m* ]
         {
) S2 U+ m7 i0 P. u: G9 G                 int abcd = GetLastError();
  S& \6 L  ]4 T. {                 printf("Process token open Error: %u\n",GetLastError());
( h) q' d! z! W$ L) [+ d8 Y9 O         }8 g9 r( E. J  C4 i* m
       DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);//创建模拟令牌# M3 V* j' U- j9 D
         int dup = GetLastError();! ^, `) }' o# M( Z$ ?, J% c
通过上面的函数我们得到了这个DuplicateTokenEx函数的最后一个参数后,我们还不能直接用,根据MSDN 的说法要用SetTokenInformation来设置一下/ ~1 W8 V0 k, O# _) c

# X# h( O4 z7 L: ~BOOL WINAPI SetTokenInformation(1 ]7 o# k2 i. w. ~
  __in          HANDLE TokenHandle,  t+ k3 W: ~! D# A5 n
  __in          TOKEN_INFORMATION_CLASS TokenInformationClass,- Q! \# L% y) i, Z6 M' V( r
  __in          LPVOID TokenInformation,
1 T1 ~  `) p2 T" T  __in          DWORD TokenInformationLength, Z7 E. Z% ~; m6 B8 n" m- o0 z
);7 }9 M& H0 B$ c* b
其中第一个参数就是我们得到Toke 的句柄,第二个参数会话ID ,也就是把会话ID 设置到备份令牌中,代码如下:0 P; n2 j" I% B  B8 w: ]7 S! X
# y- ?2 W- o/ F. Y" L8 H+ i
SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD))
% G& W# U# d8 C) s9 d; c6 ^3 e设置完成后 最好检验一下,当然不检验也没有关系了,代码如下:
$ r. ?8 U& Y' H! }) B2 A; l
8 O3 I- m% |3 p& W: {  a3 B  if(!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL)) //这个函数启用或禁止指定访问令牌的特权
5 K9 U1 a8 y, ]- a         {               
! Q* F" }8 I7 @  e                 int abc =GetLastError();  \. r' `* D& L' K
                 printf("Adjust Privilege value Error: %u\n",GetLastError());
6 {" g9 V! _' R' V1 j         }( h' I( e. D3 x# J# a8 p
         if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)7 p9 _# |5 K: h% ^# Q# R
         {, T. W0 r1 [' `% Q: b8 p
                 printf("Token does not have the provilege\n");2 c2 j/ o7 s+ A' N* O
         }
; E  k4 J, E, }, } ' v# C1 ?; b" U- H7 M& r2 e' J
这样的话CreateProcessAsUser第一个参数的工作算是正式完成,下面几个参数就简单了,
) o  B* M/ j! D- K
) J& C, w/ J! r( O! a7 n4 f: O7 p大家直接看代码吧2 R1 y% z$ e' \; s! v

5 j4 B8 z# g$ [- w- {         bResult = CreateProcessAsUser(  y% K! H# z% c0 L- h  |5 p
                 hUserTokenDup,                              // 这个参数上面已经得到! m6 k0 a' ]) F! M. n
                 _T("C:\\Windows\\System32\\notepad.exe"), //执行文件的路径5 J/ I2 s5 R6 t4 V4 y0 ~. t
                 NULL,                              // command line
2 f# o! ~$ P& L& I* _4 ]                 NULL,              // pointer to process SECURITY_ATTRIBUTES
4 Q2 B, m9 i6 ^1 b& S- k1 m$ M$ Y                 NULL,              // pointer to thread SECURITY_ATTRIBUTES6 M5 b4 o* ]% @& q; u# I5 `; j
                 FALSE,             // handles are not inheritable
8 k/ a) |5 U/ \" U; p0 P" Z                 dwCreationFlags, // creation flags
5 w# ]6 i7 x" _6 S! q4 Y# G5 b9 _                 pEnv,              // pointer to new environment block1 ]! U% Q' A3 v; ~" b; ]
                 NULL,              // name of current directory
6 R, |! }3 |& @' U) {; O' P                 &si,               // pointer to STARTUPINFO structure
' }6 r( j# v- W+ }+ ^0 P2 }$ w                 &pi                // receives information about new process. V0 _6 ~, E/ C/ h$ R% |- S
                 );8 F, m4 W1 A! E2 n' B9 O

! N3 d# _" O/ E) n) Y
; {9 l! w) v% k9 Y5 Z$ r+ D# |% O( G最后大家别忘了把打开的句柄关闭。这样看起来是不是就有点简单了,其实也没什么,剩下的就是Winodws 服务的基本框架的一些东西,那些就简单了。 以上都是自己根据MSDN理解得来的,如有什么问题欢迎大家指正!
  x# c* ]! ~# _, O6 L
  R( p4 w. D, p- s1 s! z附上Demo下载地址:http://download.csdn.net/source/3497793
发表于 2011-8-8 16:28:59 | 显示全部楼层
不錯。。。我前兩個月給OEM做的出貨用的GSensor Protect AP就是這個做法
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-4-4 20:17 , Processed in 0.301381 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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