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

以system权限启动应用程序

[复制链接]
发表于 2011-8-5 21:27:34 | 显示全部楼层 |阅读模式
最近在搞一个项目,需要程序开机自动运行,可是程序中调用了底层驱动的一些函数,必须以管理员的权限才能运行,否则程序运行不成功,在XP 下 直接写注册表就可以,可是在VISTA 和 WIN7 下写注册表的方式失效,因为必须以管理员的权限运行才可以,迫于无奈,上网查了N多资料,终于找到了一种解决的办法,在此分享出来,以此献给被此问题苦恼的人!
. C8 y, x( h3 ]; V
/ @2 d8 q7 r( h首先介绍一下,解决问题的思路,创建一个服务,安装在系统中,在服务里以SYSTEM 的权限创建一个进程,用来启动自己的应用程序,我们想什么时候启动我们的应用程序,只需要我们用应用程序给服务发送一个信号,在服务接收到信号后,就可以启动我们想要运行的应用程序了。
- p& e0 e: I: @8 p8 d: v1 s3 k; ~8 J4 S3 P$ |/ B5 R% c
实现框架如下:
; T8 X! ^; G8 ^% W% ~% J" W# H. Y* p- m  g0 q4 t
9 t) n5 }5 x1 ^* }; ?& x

& ?9 M6 A( O& N; g/ S) Z1 |所以在这里我们需要创建三个程序:1.Windows 服务程序 2.我们自己的应用程序 3.给服务发送信号的应用程序。
' U5 s/ h# d0 v# t
, @# L3 y/ A2 J当然其中的 1和3 可以合并在一起,而且 2  我们可以做成多个应用程序。这样只要是我们自己写的都可以以SYSTEM的权限运行了,比管理员更实用。这里需要注意的是第一次安装服务的时候必须以管理员的权限运行。5 L  H2 w8 T+ Z  I& p: T

4 r! V+ B, F' C7 G3 m( a3 _; G好了,闲话少说,下面步入正题,我做了个简单的Demo,是以服务的方式启动系统自带的管理记事本程序(windows 7下面的,用VS2008编辑)。
" h+ `/ @8 t5 i3 t) ?6 H* K
# [! P* E' X  l7 E我们以函数CreateProcessAsUser 来开始讲解,我们所要做的动作就是把这个函数的各个参数都填对 就OK,只需把其中的几个关键参数填好,其他设置为NULL 就OK ,
( S. i3 ^( W% h  a+ x
9 A* j& f4 J' C3 _' i首先第一个参数HANDLE hToken ,Token 句柄,怎么得到这个句柄,MSDN 给出了两种办法,一种通过调用 LogonUser函数 ,一种另外一种通过 调用DuplicateTokenEx 函数,在这里我们选择第二种方式创建一个模拟的Token,关键是这个模拟的Token那里来,那我们就得追踪DuplicateTokenEx里面的各个参数,其中DuplicateTokenEx参数如下:
- p+ C! `1 N, M) N' b5 y
/ z. e# J/ i- n6 T/ |, [BOOL WINAPI DuplicateTokenEx(' w1 E& \& Y+ s6 k6 `7 l
  __in          HANDLE hExistingToken,% q" L4 l: f- v* N8 z; R
  __in          DWORD dwDesiredAccess,
+ T( t* z5 w& D" F8 V) G  __in_opt      LPSECURITY_ATTRIBUTES lpTokenAttributes,0 O& A; e! n/ m: L* {
  __in          SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,- a, a4 p: G" P6 l6 R
  __in          TOKEN_TYPE TokenType,
, q5 G, p  t$ D: H  __out         PHANDLE phNewToken8 c# ]7 Z9 E' Y  T; v
);. U8 L: P. o" j/ p9 {4 W2 U! ~" K
这个函数的主要功能就是根据现有的Token 来创建一个新的Token,我们需要的就是这个新的Token,如何得到这个新的Token,看来我们还得往下追踪哦,第二个参数是新建Token的权限,这个参数直接设置成MAXIMUM_ALLOWED就可以,第三个参数是 安全描述符的指针,这里直接设置成NULL,分配成一个默认的安全描述符,第四个参数设置成SecurityIdentification  的OK,(安全描述符的级别)  第五个参数 Token类型 直接设置成TokenPrimary OK  因为它就是用于CreateProcessAsUser的函数的。最后一个参数就是我们想要的参数了。我们主要就是得到他,要想得到这个参数 我们必须得到第一个参数。" u. _( k4 V3 f3 P$ N& J
3 C& Q4 K7 ^0 s. C! G# u  f) u
第一个参数是一个已经存在的Token,数要想得到这个Token,必须找到以个进程,把这个进程的Token 拿过来为我们所用,得到这个Token 要运行函数OpenPrcessToken通过这个函数得到Token的句柄,但是要得到这个Token的句柄,必须要通过函数OpenProcess得到进程的句柄,要得到进程的句柄 必须通过函数ProcessIdToSessionId得到进程的ID。因为我们系统每次登入的时候都有一个winlogon.exe,我们就拿这个进程的ID 来得到CreateProcessAsUser函数的第一个参数。也就是把上面的一步步还原回去!
! L; q* }( F1 }; H
: F; a! p. m* x) m
6 L7 p) \7 W; ?3 s# P- L7 `/ H9 P# I, @* d% I, i
dwSessionId = WTSGetActiveConsoleSessionId(); //得到当前用户的会话ID                 //////////////////////////////////////////7 l: Q3 t6 E0 m- u
// Find the winlogon process, V; q9 ^1 R) b) V+ o; t' i1 r! z
////////////////////////////////////////
) I# x8 B3 j. q8 r7 rPROCESSENTRY32 procEntry;  //用来存放快照进程信息的一个结构体
" q; s. ^  B* n# g2 X. q//函数为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程[THREAD])建立一个快照[snapshot]7 J3 H$ b( |, U: i9 e$ G  o! V
     HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);7 O7 e# w7 D0 @; z
     if (hSnap == INVALID_HANDLE_VALUE)* w! [3 y; F, a9 r: j, l/ Y2 n
         {
' k. Q3 ]' k, s                 return 1 ;% g" o! y4 {( F) U- U
         }
" D! ~  T4 |* P" E/ \! D         procEntry.dwSize = sizeof(PROCESSENTRY32);
" p0 Y8 }6 |  Q, y         if (!Process32First(hSnap, &procEntry)) //获得第一个进程的句柄.7 q" l- _8 Y  R2 A, ]+ X) x
         {; p! }) m% `. Q. {! P6 `3 \; G
                 return 1 ;
& [# G  Z% F: X/ v7 M* w5 s: }6 b: J         }/ {! ?( y6 R+ I( p0 R
         do, `* @( G4 U- `, o
         {
/ V; Z5 a% f" P5 ]% Kif (_wcsicmp(procEntry.szExeFile, _T("winlogon.exe")) == 0)  //查找winlogon.exe
0 I  d) W, ?$ m" {; R: E; l         {
) S7 R( i) @) x0 P' y! T         // We found a winlogon process...make sure it's running in the console session# Q/ c2 K) m+ L
         DWORD winlogonSessId = 0;
. T. L: m, {* F1 O% E6 ?* @: x        if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId)//得到与进程ID对应的终端服务会话ID
3 F6 i* z$ c: N! _7 Y$ m0 F0 T                          {& E- {2 Q( Z- u3 D4 |' c6 d
                                   winlogonPid = procEntry.th32ProcessID;, i4 _) |9 E! M, C/ y3 I$ y, b
                                   break;" y7 h2 f7 t# z
                          }# N$ m/ D; c0 g) D3 a6 L1 k" T
                 }
, p8 i" B+ s4 O. g  _         } while (Process32Next(hSnap, &procEntry)); //获得下一个进程的句柄
; f) w, y9 N. k! |- f         ////////////////////////////////////////////////////////////////////////5 K, r* e3 H# N4 ^. d/ l
         hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);  //获得进程句柄
! X$ y' Z* `0 j5 P9 `  L1 p         if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
/ h" K; y2 b) }5 K8 j" n$ T& _                 |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID  z( i0 @& K  ]+ s* X1 M
                 |TOKEN_READ|TOKEN_WRITE,&hPToken))                //获得令牌句柄
4 x4 ]: z) A: o3 [+ b1 w% O, i* A         {; l) p% K9 ]% R7 p  R, h
                 int abcd = GetLastError();! D! f, o( j- V) D9 q# v
                 printf("Process token open Error: %u\n",GetLastError());6 E2 w6 j( L3 L2 n; G
         }
/ R1 o/ x# g) m% H' T: k$ E7 ^       DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);//创建模拟令牌
& f9 p+ J& u0 j  e) |+ G! p         int dup = GetLastError();1 ]- u5 a- m2 P! C+ q
通过上面的函数我们得到了这个DuplicateTokenEx函数的最后一个参数后,我们还不能直接用,根据MSDN 的说法要用SetTokenInformation来设置一下, ?2 A! j: X3 i; I
8 V. f, c+ n' O5 Y
BOOL WINAPI SetTokenInformation($ I- V2 f) J% D# |6 d% D* d: o; ]" C
  __in          HANDLE TokenHandle,6 Q. w; Z! k2 m5 ~) ^' A
  __in          TOKEN_INFORMATION_CLASS TokenInformationClass,
5 S( w( {/ V) B5 M1 B' k  __in          LPVOID TokenInformation,
) p" W' E; {) D5 N& }  __in          DWORD TokenInformationLength, J8 c4 o' ]' }) R3 {/ E8 ~8 I
);2 J4 {" z1 N& |: n' i
其中第一个参数就是我们得到Toke 的句柄,第二个参数会话ID ,也就是把会话ID 设置到备份令牌中,代码如下:/ F+ G- B- @8 D+ z0 _: \/ J
: {8 f+ x$ F" ?! @, u& D; U' l
SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD)): {0 t6 w5 n3 l- ^5 |: i* {
设置完成后 最好检验一下,当然不检验也没有关系了,代码如下:2 R+ ]" I* y1 d, Q

) W0 j$ x" d( e5 p  D* y  if(!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL)) //这个函数启用或禁止指定访问令牌的特权' `, r, K) R( g
         {               
0 W3 D  ^, A4 i                 int abc =GetLastError();
) c1 N" d% D% v2 p* M2 E* ^3 f% t                 printf("Adjust Privilege value Error: %u\n",GetLastError());" Y8 j& o5 V* W4 h& d( x/ {; ?
         }
' u$ O. [- i: ~         if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)8 O+ q0 o$ ?% o8 T8 _
         {, r# w+ y% u# r
                 printf("Token does not have the provilege\n");. N2 @6 v9 A* K/ c
         }
5 @! n' L; ^' J 3 V8 d! N4 `/ c& y
这样的话CreateProcessAsUser第一个参数的工作算是正式完成,下面几个参数就简单了,
/ M; w8 a/ {% }# p7 U" w
, k; k5 @% u$ ^& C. W大家直接看代码吧
( B2 f' l7 z: w* s
8 m) @/ W' G  ?/ e3 D         bResult = CreateProcessAsUser(
; P1 B$ }% `# b% C( K( P; r0 s! q                 hUserTokenDup,                              // 这个参数上面已经得到
! d* Z  Y2 h7 o- R2 t* A% F% F1 z                 _T("C:\\Windows\\System32\\notepad.exe"), //执行文件的路径
! D6 O+ u5 K8 Q: F                 NULL,                              // command line
0 W: {  X6 [4 l  S6 P% \- D                 NULL,              // pointer to process SECURITY_ATTRIBUTES
$ e) b& ~8 b& e' i                 NULL,              // pointer to thread SECURITY_ATTRIBUTES
) Y: m" N+ y* z. }                 FALSE,             // handles are not inheritable( T5 R) Y7 Q* _" C$ h3 A! S7 U( g
                 dwCreationFlags, // creation flags* H; a3 b9 E5 L( W; Z+ @1 I) ~
                 pEnv,              // pointer to new environment block
2 Q! G. z( W7 o& z8 s                 NULL,              // name of current directory
  f# D3 N1 a: S. ~" i                 &si,               // pointer to STARTUPINFO structure' P# w! n' L/ H" N
                 &pi                // receives information about new process
4 W4 E( k0 I. `$ C0 t                 );
* _' Y! u# q. E# A- H& ?+ g$ b& B
: P3 p. E6 ]8 y6 J* O/ _* O
: L/ p: Q. G* z, l* K/ M最后大家别忘了把打开的句柄关闭。这样看起来是不是就有点简单了,其实也没什么,剩下的就是Winodws 服务的基本框架的一些东西,那些就简单了。 以上都是自己根据MSDN理解得来的,如有什么问题欢迎大家指正!" W$ v9 |1 O1 \  ~6 R0 J* R* @

! t$ g9 ^6 `3 T  ~附上Demo下载地址:http://download.csdn.net/source/3497793
发表于 2011-8-8 16:28:59 | 显示全部楼层
不錯。。。我前兩個月給OEM做的出貨用的GSensor Protect AP就是這個做法
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-5-14 09:05 , Processed in 0.039700 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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