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

以system权限启动应用程序

[复制链接]
发表于 2011-8-5 21:27:34 | 显示全部楼层 |阅读模式
最近在搞一个项目,需要程序开机自动运行,可是程序中调用了底层驱动的一些函数,必须以管理员的权限才能运行,否则程序运行不成功,在XP 下 直接写注册表就可以,可是在VISTA 和 WIN7 下写注册表的方式失效,因为必须以管理员的权限运行才可以,迫于无奈,上网查了N多资料,终于找到了一种解决的办法,在此分享出来,以此献给被此问题苦恼的人!
: Q- i8 r; |. H! F7 w- h! L2 H, q; u4 G, Z: O1 v
首先介绍一下,解决问题的思路,创建一个服务,安装在系统中,在服务里以SYSTEM 的权限创建一个进程,用来启动自己的应用程序,我们想什么时候启动我们的应用程序,只需要我们用应用程序给服务发送一个信号,在服务接收到信号后,就可以启动我们想要运行的应用程序了。7 b( V9 g/ Q5 G* [

: p: a- U% o0 g实现框架如下:
/ z$ n- }7 `. C$ A2 D1 ]# Z; C( ^# J" w- h

+ |* ~) X  p, r0 d% j1 L5 l  U2 O6 W7 W" Q$ G& C6 `( A$ N
所以在这里我们需要创建三个程序:1.Windows 服务程序 2.我们自己的应用程序 3.给服务发送信号的应用程序。! a  s8 x7 ]2 y- p% L2 a

3 \/ k: i' }' X2 p6 r2 a当然其中的 1和3 可以合并在一起,而且 2  我们可以做成多个应用程序。这样只要是我们自己写的都可以以SYSTEM的权限运行了,比管理员更实用。这里需要注意的是第一次安装服务的时候必须以管理员的权限运行。* S; a( U, }3 \5 q9 y3 F
" t! @6 i+ H+ z8 [/ Z
好了,闲话少说,下面步入正题,我做了个简单的Demo,是以服务的方式启动系统自带的管理记事本程序(windows 7下面的,用VS2008编辑)。7 ^. G; F+ _( T! R" I

4 K  |% O: E5 h" y2 C9 Q我们以函数CreateProcessAsUser 来开始讲解,我们所要做的动作就是把这个函数的各个参数都填对 就OK,只需把其中的几个关键参数填好,其他设置为NULL 就OK ,: r4 x% z+ Z) q" u1 J8 m
8 H+ }$ R% w4 f& K, b6 Z
首先第一个参数HANDLE hToken ,Token 句柄,怎么得到这个句柄,MSDN 给出了两种办法,一种通过调用 LogonUser函数 ,一种另外一种通过 调用DuplicateTokenEx 函数,在这里我们选择第二种方式创建一个模拟的Token,关键是这个模拟的Token那里来,那我们就得追踪DuplicateTokenEx里面的各个参数,其中DuplicateTokenEx参数如下:+ V* E7 W* W7 t

: B) l' f' K9 a: E3 |4 A5 `BOOL WINAPI DuplicateTokenEx(  L; N: H- V+ G7 N% T) \
  __in          HANDLE hExistingToken,  }3 \2 ]/ {8 O
  __in          DWORD dwDesiredAccess,0 p. p' B9 y1 K3 ^
  __in_opt      LPSECURITY_ATTRIBUTES lpTokenAttributes,
+ y0 W# H7 o" a+ L& {* q6 b  __in          SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,6 o) Y  o) V$ n2 d
  __in          TOKEN_TYPE TokenType,- Q6 |+ W& N- O* ?5 Z- M4 |
  __out         PHANDLE phNewToken3 R' O2 f5 Y1 V: T8 k; c8 }4 s3 O
);
/ V3 o1 o" S: ]/ e4 C" r这个函数的主要功能就是根据现有的Token 来创建一个新的Token,我们需要的就是这个新的Token,如何得到这个新的Token,看来我们还得往下追踪哦,第二个参数是新建Token的权限,这个参数直接设置成MAXIMUM_ALLOWED就可以,第三个参数是 安全描述符的指针,这里直接设置成NULL,分配成一个默认的安全描述符,第四个参数设置成SecurityIdentification  的OK,(安全描述符的级别)  第五个参数 Token类型 直接设置成TokenPrimary OK  因为它就是用于CreateProcessAsUser的函数的。最后一个参数就是我们想要的参数了。我们主要就是得到他,要想得到这个参数 我们必须得到第一个参数。
, I. U2 `' @* r, V& P* q6 S
/ z1 E) J- }$ \# z/ N/ {+ P第一个参数是一个已经存在的Token,数要想得到这个Token,必须找到以个进程,把这个进程的Token 拿过来为我们所用,得到这个Token 要运行函数OpenPrcessToken通过这个函数得到Token的句柄,但是要得到这个Token的句柄,必须要通过函数OpenProcess得到进程的句柄,要得到进程的句柄 必须通过函数ProcessIdToSessionId得到进程的ID。因为我们系统每次登入的时候都有一个winlogon.exe,我们就拿这个进程的ID 来得到CreateProcessAsUser函数的第一个参数。也就是把上面的一步步还原回去!, Y' E8 g) S, q: Z
, A6 c0 K' L- }( A) Q) f4 F: o2 T

; C. {  \+ s3 \5 V" n, Q$ S% J! X- z8 K  u- O# m3 s0 A
dwSessionId = WTSGetActiveConsoleSessionId(); //得到当前用户的会话ID                 //////////////////////////////////////////: @0 I$ {: M$ K9 E: \
// Find the winlogon process% e" o- S/ o7 V6 t/ S
////////////////////////////////////////- M7 G" n9 l+ I: H# @! a
PROCESSENTRY32 procEntry;  //用来存放快照进程信息的一个结构体4 v) g# @  J3 l; e; }5 E  j8 G
//函数为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程[THREAD])建立一个快照[snapshot]
  \2 S2 q. z' X3 X( N1 K     HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);! X* A# X, {$ ^: X3 K/ b; [
     if (hSnap == INVALID_HANDLE_VALUE)
9 a9 Q! s9 e3 a- S  W6 S         {/ O# B) L! F3 n! H# {+ ]' n1 O, h
                 return 1 ;
7 |8 c0 u. B2 R         }
& W* b! g1 w7 {* |5 Z: ~+ g$ X         procEntry.dwSize = sizeof(PROCESSENTRY32);
" m' |* Q$ H  K0 s) U8 E         if (!Process32First(hSnap, &procEntry)) //获得第一个进程的句柄.
2 P) r9 W& u' ~7 }/ U/ A         {
: `% D, q. f& a0 ~+ i0 j                 return 1 ;
9 R/ C5 z/ Z  L4 @2 X1 r& L; y         }
2 M) M. R( F: X- T4 a         do/ }7 C! u$ Z0 `) |' k
         {
8 }0 F- _- \* Nif (_wcsicmp(procEntry.szExeFile, _T("winlogon.exe")) == 0)  //查找winlogon.exe
7 Z6 ?% N' D" k' b         {
( R* o. j% w3 B8 N. c  |9 Q         // We found a winlogon process...make sure it's running in the console session8 `6 ^5 G# u2 N* q
         DWORD winlogonSessId = 0;+ I5 b- D% _3 a/ D6 z4 z
        if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId)//得到与进程ID对应的终端服务会话ID
5 G9 |- m, C$ ?1 R, U3 s7 R6 e$ Q0 C                          {. c7 p& \" s9 o& ~6 c3 T
                                   winlogonPid = procEntry.th32ProcessID;
: X0 z3 f: Z- Y                                   break;
2 Y" O8 w3 U  R# ^2 P7 v                          }6 u7 s4 }1 }* U
                 }' R- a$ e# ~: v' z2 P7 O
         } while (Process32Next(hSnap, &procEntry)); //获得下一个进程的句柄
4 t2 |9 |6 p$ Y/ Z; X5 i! R         ////////////////////////////////////////////////////////////////////////0 \  W; h+ C& d
         hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);  //获得进程句柄8 U! l7 J' J+ W! j) t
         if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
9 ?& F0 [4 b2 ?# @0 x- F                 |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID8 V& n* S: Y4 J# x6 m5 s
                 |TOKEN_READ|TOKEN_WRITE,&hPToken))                //获得令牌句柄
- K1 c# v7 |! u) m         {
# V4 \9 u1 ]+ b7 \( H* h                 int abcd = GetLastError();& P7 B4 ~: m% _& P
                 printf("Process token open Error: %u\n",GetLastError());
" N1 z1 P) @# h0 i% X& d2 l         }
# Z2 T2 {0 {9 ]7 a5 [, q6 v* {& A       DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);//创建模拟令牌2 ~" i7 S- J2 c: I
         int dup = GetLastError();: D0 K% A) C( B. i4 Y% H9 ]/ J( v/ @
通过上面的函数我们得到了这个DuplicateTokenEx函数的最后一个参数后,我们还不能直接用,根据MSDN 的说法要用SetTokenInformation来设置一下
) ~8 r+ I/ U8 F. o0 k5 ^% _
/ E% _9 `$ x( \4 G2 bBOOL WINAPI SetTokenInformation(9 w' q+ G& s5 _
  __in          HANDLE TokenHandle,
! W8 H9 q  G: f2 _  __in          TOKEN_INFORMATION_CLASS TokenInformationClass,6 ?* W. N" a( j( s6 V5 o1 A  Z
  __in          LPVOID TokenInformation,
4 j1 t4 Y/ I$ _% b3 J. j2 Q  __in          DWORD TokenInformationLength2 }+ b0 f% k6 B* f* Y0 g
);
  F; C3 ^8 u' M) y其中第一个参数就是我们得到Toke 的句柄,第二个参数会话ID ,也就是把会话ID 设置到备份令牌中,代码如下:
0 D  a3 X1 X+ A6 t: [9 d
) m" c9 }( }; zSetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD))
/ h+ u$ b1 Y& i) p- T! b: D4 ?8 `设置完成后 最好检验一下,当然不检验也没有关系了,代码如下:
( x9 e9 r* b$ K( F; Z3 g" u8 D8 a8 k! S" y! `; O
  if(!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL)) //这个函数启用或禁止指定访问令牌的特权
5 K# |# I2 P! N! z: J& `8 s         {               , y) y/ v- I; w
                 int abc =GetLastError();
* j: O$ q# k% y                 printf("Adjust Privilege value Error: %u\n",GetLastError());1 e: M1 f" O. n# b
         }7 r4 J4 u; K6 x; q
         if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)* C# s' \  x3 j. l$ c
         {, d/ H( n8 O1 M' R7 y; M
                 printf("Token does not have the provilege\n");
6 P1 N: \# u/ |' Q% [. g         }/ l. W# O% E  I" T
) V, `9 B0 R# ~! i
这样的话CreateProcessAsUser第一个参数的工作算是正式完成,下面几个参数就简单了,
& A9 ]+ w/ O! k) K% r4 T# T
$ A8 K2 C2 V0 @5 Z! [3 X  Z大家直接看代码吧
) t5 G. U; ~7 K$ d; @
0 I7 K% u8 [  \4 u; F+ B         bResult = CreateProcessAsUser(
& Q! m8 {' }4 M( G$ P5 n0 T" Y7 ]                 hUserTokenDup,                              // 这个参数上面已经得到
5 _! e( C6 Y8 H                 _T("C:\\Windows\\System32\\notepad.exe"), //执行文件的路径$ R: l/ U$ V, _/ T) D. o& k
                 NULL,                              // command line
4 p: `7 H: a8 f/ v! b0 }$ |* K; }                 NULL,              // pointer to process SECURITY_ATTRIBUTES
% r4 d0 D. C- E8 u0 ]" J                 NULL,              // pointer to thread SECURITY_ATTRIBUTES3 D, p2 b9 I5 `/ L* Y% D
                 FALSE,             // handles are not inheritable
. {1 d8 q9 S$ \3 d3 P% I) _4 l                 dwCreationFlags, // creation flags7 i$ y+ u; Y. a0 C
                 pEnv,              // pointer to new environment block
& c4 l, @7 v! j+ q                 NULL,              // name of current directory$ _$ i, E$ Y; s& Q. N
                 &si,               // pointer to STARTUPINFO structure0 P, t9 ]9 A& \# C( H. e1 ~3 U
                 &pi                // receives information about new process
; a0 M3 T1 }, n- @9 b                 );
) m: H. ^+ P6 v0 ^+ I  o
& [  U0 a4 Q, W) H) c% q6 _/ H" {4 N: l9 Q* Q& I7 N0 L; `  ?3 X
最后大家别忘了把打开的句柄关闭。这样看起来是不是就有点简单了,其实也没什么,剩下的就是Winodws 服务的基本框架的一些东西,那些就简单了。 以上都是自己根据MSDN理解得来的,如有什么问题欢迎大家指正!; z' @- F( C0 }

+ w0 d! g; B* Z" M- S4 T: R( u1 c附上Demo下载地址:http://download.csdn.net/source/3497793
发表于 2011-8-8 16:28:59 | 显示全部楼层
不錯。。。我前兩個月給OEM做的出貨用的GSensor Protect AP就是這個做法
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-20 08:37 , Processed in 0.068858 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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