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

以system权限启动应用程序

[复制链接]
发表于 2011-8-5 21:27:34 | 显示全部楼层 |阅读模式
最近在搞一个项目,需要程序开机自动运行,可是程序中调用了底层驱动的一些函数,必须以管理员的权限才能运行,否则程序运行不成功,在XP 下 直接写注册表就可以,可是在VISTA 和 WIN7 下写注册表的方式失效,因为必须以管理员的权限运行才可以,迫于无奈,上网查了N多资料,终于找到了一种解决的办法,在此分享出来,以此献给被此问题苦恼的人!
+ ]' |/ l1 A2 d: ~; M; \1 B$ e% s3 j. V
首先介绍一下,解决问题的思路,创建一个服务,安装在系统中,在服务里以SYSTEM 的权限创建一个进程,用来启动自己的应用程序,我们想什么时候启动我们的应用程序,只需要我们用应用程序给服务发送一个信号,在服务接收到信号后,就可以启动我们想要运行的应用程序了。
1 r( ~% q& @) t/ s) H: i  u; O
4 H* y+ b% ^- J* F实现框架如下:
7 i: M# V6 x. P7 q- r2 t
* ^3 y1 K/ m9 J3 O% y & p; S0 I! i% G8 c: y5 D
, D  [/ i0 r9 }1 }6 c  a2 f$ B
所以在这里我们需要创建三个程序:1.Windows 服务程序 2.我们自己的应用程序 3.给服务发送信号的应用程序。3 d$ A: P! e! w! _+ W0 F0 O2 U

0 P1 Z3 }5 w5 K6 x, G8 |当然其中的 1和3 可以合并在一起,而且 2  我们可以做成多个应用程序。这样只要是我们自己写的都可以以SYSTEM的权限运行了,比管理员更实用。这里需要注意的是第一次安装服务的时候必须以管理员的权限运行。0 }. J& _+ B6 {

$ u  |- J+ W6 p8 R好了,闲话少说,下面步入正题,我做了个简单的Demo,是以服务的方式启动系统自带的管理记事本程序(windows 7下面的,用VS2008编辑)。3 X' o5 v9 @  y

* c5 H6 G+ G) o3 Q$ O我们以函数CreateProcessAsUser 来开始讲解,我们所要做的动作就是把这个函数的各个参数都填对 就OK,只需把其中的几个关键参数填好,其他设置为NULL 就OK ,
3 `1 Q8 A* v1 g4 l
3 R' @& B& z" c: e- O; P首先第一个参数HANDLE hToken ,Token 句柄,怎么得到这个句柄,MSDN 给出了两种办法,一种通过调用 LogonUser函数 ,一种另外一种通过 调用DuplicateTokenEx 函数,在这里我们选择第二种方式创建一个模拟的Token,关键是这个模拟的Token那里来,那我们就得追踪DuplicateTokenEx里面的各个参数,其中DuplicateTokenEx参数如下:
% ]1 n' S9 [% ~2 T. I
8 k5 Y7 B3 i4 p* }% F! KBOOL WINAPI DuplicateTokenEx(
) Y( a  L" {3 p- m4 d  __in          HANDLE hExistingToken,* V# b0 i4 x/ o! F$ b
  __in          DWORD dwDesiredAccess,
8 \) ]# g' `& o  __in_opt      LPSECURITY_ATTRIBUTES lpTokenAttributes,
! y1 h5 B% f+ d# U9 M- j: l  l- \4 D  __in          SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
/ B# D2 K% r" ]* R$ \1 p& e5 G8 Q  __in          TOKEN_TYPE TokenType,
! p$ d0 M" h2 B# y; g0 r  __out         PHANDLE phNewToken
, A& |* U, i1 ^( A5 n9 M; l5 g);$ _. i! e. S: p. j( r
这个函数的主要功能就是根据现有的Token 来创建一个新的Token,我们需要的就是这个新的Token,如何得到这个新的Token,看来我们还得往下追踪哦,第二个参数是新建Token的权限,这个参数直接设置成MAXIMUM_ALLOWED就可以,第三个参数是 安全描述符的指针,这里直接设置成NULL,分配成一个默认的安全描述符,第四个参数设置成SecurityIdentification  的OK,(安全描述符的级别)  第五个参数 Token类型 直接设置成TokenPrimary OK  因为它就是用于CreateProcessAsUser的函数的。最后一个参数就是我们想要的参数了。我们主要就是得到他,要想得到这个参数 我们必须得到第一个参数。
2 J7 d& G# l1 B5 z# `' o- `
3 Q' F5 O4 @; Q9 w第一个参数是一个已经存在的Token,数要想得到这个Token,必须找到以个进程,把这个进程的Token 拿过来为我们所用,得到这个Token 要运行函数OpenPrcessToken通过这个函数得到Token的句柄,但是要得到这个Token的句柄,必须要通过函数OpenProcess得到进程的句柄,要得到进程的句柄 必须通过函数ProcessIdToSessionId得到进程的ID。因为我们系统每次登入的时候都有一个winlogon.exe,我们就拿这个进程的ID 来得到CreateProcessAsUser函数的第一个参数。也就是把上面的一步步还原回去!
! m" Z7 u* {3 N0 q# |
( O9 x% o' O  M* m; k& b) J ) b' ^! R! x4 a  f9 S% A6 r/ x: k/ a

/ v$ E: v7 a& [% d6 R: H0 ZdwSessionId = WTSGetActiveConsoleSessionId(); //得到当前用户的会话ID                 //////////////////////////////////////////
, ?0 W. Y# f) T2 F, N1 x( f: x// Find the winlogon process
; e/ s2 F7 t6 G; K( f1 P' C////////////////////////////////////////
- \* F6 y1 f8 z& Q, g+ o; ?/ I2 XPROCESSENTRY32 procEntry;  //用来存放快照进程信息的一个结构体' b" t7 r* \2 B9 m+ D' f- f3 u" @
//函数为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程[THREAD])建立一个快照[snapshot]
& F0 Y9 s6 o3 e  Y% V& V: a     HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);0 Q, t& s; c7 j9 d3 M" m' E6 R+ Z
     if (hSnap == INVALID_HANDLE_VALUE)/ ^+ ]* @6 }8 ~4 X1 ]
         {. R0 U( X2 S) h1 u/ Q2 N
                 return 1 ;1 B$ p- d  {# B; A2 c
         }
3 V+ h1 r" \0 j, l! b, B, b         procEntry.dwSize = sizeof(PROCESSENTRY32);
! i" ?; ?$ r: q" [! g! ~; T5 W* [         if (!Process32First(hSnap, &procEntry)) //获得第一个进程的句柄.
5 P% L! q* {0 C* G         {
  V8 B/ R- h, L                 return 1 ;
, H% x$ i2 t* N; b( M- s         }
" Z5 w+ {$ c: t: q# ]: a         do# T* q! L$ N& @
         {
9 n  e" j) k( i8 U' w; P# `+ {if (_wcsicmp(procEntry.szExeFile, _T("winlogon.exe")) == 0)  //查找winlogon.exe$ u& j& i" j8 l" a2 C
         {# _8 G( l7 x( j5 x: @  @5 O
         // We found a winlogon process...make sure it's running in the console session
) ~* O) O. Y. I3 s         DWORD winlogonSessId = 0;
  {3 I# y) `" ]: a        if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId)//得到与进程ID对应的终端服务会话ID
4 T+ i3 i) t5 ?4 q. `7 x3 N7 h                          {
+ G8 ^6 W# q' Y8 K; P! Z0 Q$ r                                   winlogonPid = procEntry.th32ProcessID;
  n3 J6 ~$ x# P! q1 q' U  \                                   break;
  |9 m/ Q2 d6 M  [, V3 N                          }; u5 }9 L) |: f) q4 l3 S1 k
                 }
& Q, ]2 k$ L4 V) R' _% `6 j+ g         } while (Process32Next(hSnap, &procEntry)); //获得下一个进程的句柄
- b/ q& ~) f- b' i6 B9 u( L/ T         ////////////////////////////////////////////////////////////////////////: K' d/ I2 C" n3 Q6 D" S9 E4 X' e! c
         hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);  //获得进程句柄& p, V8 J0 @" S5 T/ f2 T: M. S
         if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY4 N/ x" [6 }* h2 h* }# H3 m
                 |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID# C1 q6 a- `  j. d
                 |TOKEN_READ|TOKEN_WRITE,&hPToken))                //获得令牌句柄5 Q1 z1 ^2 m' ^
         {. m1 W3 n8 T+ H1 Z
                 int abcd = GetLastError();
6 r7 g, d) k1 Y3 A6 Z0 N( R+ ?                 printf("Process token open Error: %u\n",GetLastError());
3 R* I6 h; f* Z         }4 {" s. w- P/ D1 G# {
       DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);//创建模拟令牌
7 V4 \- D1 U8 X2 `  m1 x         int dup = GetLastError();3 L( X. y  d( S( m
通过上面的函数我们得到了这个DuplicateTokenEx函数的最后一个参数后,我们还不能直接用,根据MSDN 的说法要用SetTokenInformation来设置一下
$ V* P; G- u+ e& l( x" C* T$ g# ?0 O- b: R6 a) [7 e1 g
BOOL WINAPI SetTokenInformation(
- w$ a8 u) n: \  __in          HANDLE TokenHandle,( E) H8 W5 i3 l* d: }8 K3 T, {
  __in          TOKEN_INFORMATION_CLASS TokenInformationClass,
4 p/ N; R# o8 Q8 h7 D  __in          LPVOID TokenInformation,
! k4 c) s- x' B4 Z8 b' c1 A/ I) G  __in          DWORD TokenInformationLength& E- p) f& Q& w! o' h! W
);
3 \3 x/ _( W5 u0 E3 |1 H  H其中第一个参数就是我们得到Toke 的句柄,第二个参数会话ID ,也就是把会话ID 设置到备份令牌中,代码如下:2 Q2 i7 J! ?5 U3 t  O

( Y2 i2 _9 \8 n$ ?- N& ?; MSetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD))
2 z; K% `* f) x7 ?, }9 e设置完成后 最好检验一下,当然不检验也没有关系了,代码如下:. n# b3 @% S$ f# L" k! \

0 K* V9 W# T/ m  if(!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL)) //这个函数启用或禁止指定访问令牌的特权6 T7 D# `5 C5 J5 J: X
         {                 l9 l' h2 ~& \% f; U
                 int abc =GetLastError();; d/ R# f2 G1 F" c/ }) A! s
                 printf("Adjust Privilege value Error: %u\n",GetLastError());- m1 b9 ?" h, K% m, i* k; D
         }
) f5 k2 b- K, J9 _7 o         if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)
9 V! C: j- I5 [- H7 U! c# a1 ]$ m         {
$ R; T) |7 o  ~0 G# I                 printf("Token does not have the provilege\n");
& c8 S; c& H3 s) j0 G; q  ]( l         }
9 ]4 s2 |$ N- L. n1 W: N  i% J
1 c; q4 I! F3 o9 C7 o# [这样的话CreateProcessAsUser第一个参数的工作算是正式完成,下面几个参数就简单了,% O2 X7 H  V8 {+ c# G2 I
, I1 s& a  t3 ~; g, r
大家直接看代码吧
% A% x3 n( H( F! o9 [
& H# @6 m/ A2 H5 W         bResult = CreateProcessAsUser(2 D7 B9 C" R+ T6 Y1 m
                 hUserTokenDup,                              // 这个参数上面已经得到
; j3 X& R$ L% R/ [. y4 W3 H7 {( d                 _T("C:\\Windows\\System32\\notepad.exe"), //执行文件的路径: A  k( B4 X: z, F2 F! a& S
                 NULL,                              // command line9 g- Q3 N) }& Q1 i5 R" ?* L+ Q; a& I- Y
                 NULL,              // pointer to process SECURITY_ATTRIBUTES8 ?1 F" R4 b0 I( q
                 NULL,              // pointer to thread SECURITY_ATTRIBUTES8 P+ b  Z9 y" a  H0 [' @
                 FALSE,             // handles are not inheritable. |6 J. x( e- L9 b" j
                 dwCreationFlags, // creation flags( T& ]2 H2 G; {' R4 Y0 O
                 pEnv,              // pointer to new environment block
% m! v  i8 O4 N+ F, q% ^                 NULL,              // name of current directory
2 J9 k' V- G+ {/ ]# r7 K1 u                 &si,               // pointer to STARTUPINFO structure
; w7 o/ B' z6 D, m! w& a8 q                 &pi                // receives information about new process
* Q& R; ?$ v$ i# ^/ F                 );
7 w. }8 ]: b. p7 V/ P6 Z/ x& W- t 8 z+ G( W3 z: a. K/ I
7 T; C; I+ B0 j- ]
最后大家别忘了把打开的句柄关闭。这样看起来是不是就有点简单了,其实也没什么,剩下的就是Winodws 服务的基本框架的一些东西,那些就简单了。 以上都是自己根据MSDN理解得来的,如有什么问题欢迎大家指正!8 x$ ]6 f( w3 f' [
" A! R0 I2 _' ~2 Z; `9 [0 }& k
附上Demo下载地址:http://download.csdn.net/source/3497793
发表于 2011-8-8 16:28:59 | 显示全部楼层
不錯。。。我前兩個月給OEM做的出貨用的GSensor Protect AP就是這個做法
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-21 09:20 , Processed in 0.064858 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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