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

以system权限启动应用程序

[复制链接]
发表于 2011-8-5 21:27:34 | 显示全部楼层 |阅读模式
最近在搞一个项目,需要程序开机自动运行,可是程序中调用了底层驱动的一些函数,必须以管理员的权限才能运行,否则程序运行不成功,在XP 下 直接写注册表就可以,可是在VISTA 和 WIN7 下写注册表的方式失效,因为必须以管理员的权限运行才可以,迫于无奈,上网查了N多资料,终于找到了一种解决的办法,在此分享出来,以此献给被此问题苦恼的人!
: }1 C. o6 ?0 v. W8 S  y# C; y0 v" N; `/ d& {; {/ @
首先介绍一下,解决问题的思路,创建一个服务,安装在系统中,在服务里以SYSTEM 的权限创建一个进程,用来启动自己的应用程序,我们想什么时候启动我们的应用程序,只需要我们用应用程序给服务发送一个信号,在服务接收到信号后,就可以启动我们想要运行的应用程序了。
( J( K) V9 i* @& P0 ^6 G& t9 U$ E/ v, }
实现框架如下:
; F8 a7 z0 @! ?, w
+ t' N# c  m  o+ I* w* S3 |5 N5 G# F
' J8 V( }6 G( Q" y& t9 {
/ J! ^# j3 w! u' O所以在这里我们需要创建三个程序:1.Windows 服务程序 2.我们自己的应用程序 3.给服务发送信号的应用程序。6 N# g2 I% ~& i/ S4 L
6 M. D! W% R) h) l' ^/ T  j0 L! w
当然其中的 1和3 可以合并在一起,而且 2  我们可以做成多个应用程序。这样只要是我们自己写的都可以以SYSTEM的权限运行了,比管理员更实用。这里需要注意的是第一次安装服务的时候必须以管理员的权限运行。
6 y, N2 b2 f: Q; e0 O9 }+ X: u) F2 {
; X: b( @1 R0 K3 ]4 D3 c好了,闲话少说,下面步入正题,我做了个简单的Demo,是以服务的方式启动系统自带的管理记事本程序(windows 7下面的,用VS2008编辑)。+ z: {0 i4 h" q4 |2 ]. t2 @' U
0 B3 e8 X: G! v- G
我们以函数CreateProcessAsUser 来开始讲解,我们所要做的动作就是把这个函数的各个参数都填对 就OK,只需把其中的几个关键参数填好,其他设置为NULL 就OK ,
( A4 E! O0 A" k0 ]& w# J& D6 S# ]) T5 P( O0 F
首先第一个参数HANDLE hToken ,Token 句柄,怎么得到这个句柄,MSDN 给出了两种办法,一种通过调用 LogonUser函数 ,一种另外一种通过 调用DuplicateTokenEx 函数,在这里我们选择第二种方式创建一个模拟的Token,关键是这个模拟的Token那里来,那我们就得追踪DuplicateTokenEx里面的各个参数,其中DuplicateTokenEx参数如下:
0 o. R  D& E5 r6 u
+ }& r9 z* ^, s7 b& t. mBOOL WINAPI DuplicateTokenEx(
# i& Q! z/ O% n$ l2 W0 M2 I  __in          HANDLE hExistingToken,
0 D/ E- ]) n' B0 d$ D  W: P  __in          DWORD dwDesiredAccess,( i4 D/ Y, ^9 X0 f
  __in_opt      LPSECURITY_ATTRIBUTES lpTokenAttributes,9 g2 A" I2 A! s: W9 s
  __in          SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,% ~" h, t1 @) ]6 S8 N) c: \9 c- F
  __in          TOKEN_TYPE TokenType,* w7 p7 ~: q- f
  __out         PHANDLE phNewToken: I1 D: \8 G+ N! |0 o
);& |6 D: \( N# g- c, P' w
这个函数的主要功能就是根据现有的Token 来创建一个新的Token,我们需要的就是这个新的Token,如何得到这个新的Token,看来我们还得往下追踪哦,第二个参数是新建Token的权限,这个参数直接设置成MAXIMUM_ALLOWED就可以,第三个参数是 安全描述符的指针,这里直接设置成NULL,分配成一个默认的安全描述符,第四个参数设置成SecurityIdentification  的OK,(安全描述符的级别)  第五个参数 Token类型 直接设置成TokenPrimary OK  因为它就是用于CreateProcessAsUser的函数的。最后一个参数就是我们想要的参数了。我们主要就是得到他,要想得到这个参数 我们必须得到第一个参数。
' N5 Y9 b! W; U* M0 Z# r& C3 |. z! M8 A& K# w
第一个参数是一个已经存在的Token,数要想得到这个Token,必须找到以个进程,把这个进程的Token 拿过来为我们所用,得到这个Token 要运行函数OpenPrcessToken通过这个函数得到Token的句柄,但是要得到这个Token的句柄,必须要通过函数OpenProcess得到进程的句柄,要得到进程的句柄 必须通过函数ProcessIdToSessionId得到进程的ID。因为我们系统每次登入的时候都有一个winlogon.exe,我们就拿这个进程的ID 来得到CreateProcessAsUser函数的第一个参数。也就是把上面的一步步还原回去!! E$ P8 o: B; i/ `& c
' g) T$ c1 e' s+ w  B; [! i) v
4 _3 {) J8 \! ~$ q
3 K+ I; D- q( X; j  O# x
dwSessionId = WTSGetActiveConsoleSessionId(); //得到当前用户的会话ID                 //////////////////////////////////////////
8 X7 M3 a2 Z/ ]+ E6 _// Find the winlogon process8 I: h: f! q4 x/ X. v; W
////////////////////////////////////////
# x! M8 S; h9 j  XPROCESSENTRY32 procEntry;  //用来存放快照进程信息的一个结构体6 z  _7 i4 c7 }. Y
//函数为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程[THREAD])建立一个快照[snapshot]8 u& H) P3 x' d3 N8 X& s3 x& W
     HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
: K0 h3 f$ s# |' q     if (hSnap == INVALID_HANDLE_VALUE)
) q( O2 s/ s& o: y5 Q3 L5 E         {& z# z- u8 x, V( Y4 x6 T
                 return 1 ;
' B2 ~2 v: P. l* x* k         }' R( u0 f) v/ Z" K1 M0 ]6 Q& C
         procEntry.dwSize = sizeof(PROCESSENTRY32);
: R! l8 S& H: M! |) d         if (!Process32First(hSnap, &procEntry)) //获得第一个进程的句柄.+ ~; z$ e3 `8 B
         {" j" x" N  S, `3 C6 L* k
                 return 1 ;
! O  ]! Q9 k' {         }
# ~( @; J3 A8 |- V$ x& {3 Q$ A         do
7 p4 }0 e( O0 j; R3 _, S. b) D         {8 i6 m4 A  t/ z+ N8 b7 _1 g6 P8 C
if (_wcsicmp(procEntry.szExeFile, _T("winlogon.exe")) == 0)  //查找winlogon.exe8 {* x# F  \1 ?8 G. r' O9 D9 ~
         {* Z; W8 T' M+ @& ^# v! K
         // We found a winlogon process...make sure it's running in the console session$ _$ S* c; ^: i) u$ k
         DWORD winlogonSessId = 0;& X1 c6 m  z+ r  ~9 L' v
        if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId)//得到与进程ID对应的终端服务会话ID
- I4 |8 U. W8 t4 p                          {! Q/ q+ t0 Y5 Y1 o2 A- K" P8 i
                                   winlogonPid = procEntry.th32ProcessID;9 @8 O# f$ L  t3 M
                                   break;/ g6 p; ~( K7 u: Z
                          }. I4 k, e) O8 _  }' U6 k" S
                 }/ K2 G( Z! J2 D( D1 x
         } while (Process32Next(hSnap, &procEntry)); //获得下一个进程的句柄5 Q; v! P' T; {& c' d3 c5 r
         ////////////////////////////////////////////////////////////////////////
5 Z: ?. h/ k& E         hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);  //获得进程句柄
& }: v( u# M/ Q         if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
" ^6 O' M5 E. c3 t8 E                 |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID1 G- w- l) z* I$ Q
                 |TOKEN_READ|TOKEN_WRITE,&hPToken))                //获得令牌句柄( {* g4 K1 K2 M. q- m. W+ I- d/ S
         {
& K5 r& w2 k* o' N4 e: s+ }% d! H7 Q                 int abcd = GetLastError();6 S" X, o/ ~) R5 V8 N  h9 E! g! i
                 printf("Process token open Error: %u\n",GetLastError());
  x6 {/ q8 ~2 Y$ y( f1 ?         }
% L+ V5 X+ M% E( g       DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);//创建模拟令牌! P9 }' T0 W/ u1 Y
         int dup = GetLastError();1 q4 y* u; w3 h5 j
通过上面的函数我们得到了这个DuplicateTokenEx函数的最后一个参数后,我们还不能直接用,根据MSDN 的说法要用SetTokenInformation来设置一下9 Z' g; X0 R+ U: Q

0 q$ h4 T* {+ h9 B1 I2 x6 `BOOL WINAPI SetTokenInformation(
+ b5 T  D& R3 I% X" y* Q  __in          HANDLE TokenHandle,
2 k/ ~# g; Z* o% s9 K* G' N0 w  __in          TOKEN_INFORMATION_CLASS TokenInformationClass,% P0 l% w3 S3 t% f
  __in          LPVOID TokenInformation,
+ S! Y% A- j6 C( @, w$ v7 T  __in          DWORD TokenInformationLength
4 U; k0 S) w( G! L% T; G7 G);
4 A& R+ G+ u' h9 w  V其中第一个参数就是我们得到Toke 的句柄,第二个参数会话ID ,也就是把会话ID 设置到备份令牌中,代码如下:" M  [  w7 f+ _1 V5 ?# ^
2 W( q& l4 J, s/ {3 k  p. n
SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD))
5 ~& z1 C- W; h$ M3 q8 `设置完成后 最好检验一下,当然不检验也没有关系了,代码如下:6 ?, e3 P8 q, _8 _: E, V
: M" _+ _8 H( v$ p0 |
  if(!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL)) //这个函数启用或禁止指定访问令牌的特权
. d% n# r2 f' @/ @. q4 m" N         {               9 A; d) v" P! v0 _$ k* m
                 int abc =GetLastError();
# U/ Q4 _8 a; Y+ e% j                 printf("Adjust Privilege value Error: %u\n",GetLastError());( Z. @. X; j' z& L" v! ]6 d
         }
: t2 h. f1 J, A  o         if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)! Y; P! ^/ a4 n1 t) G3 X7 n
         {
* k+ j/ t3 p5 Y4 E2 B6 f) |; ]                 printf("Token does not have the provilege\n");$ u$ d. F( }( `3 u' X0 N
         }2 D. O9 S* Z( U% ~
& R. a5 H3 l, y* m/ f$ s
这样的话CreateProcessAsUser第一个参数的工作算是正式完成,下面几个参数就简单了,/ N7 a- W: {! V

3 Y6 X2 d' t# K. W7 F8 \- w) P大家直接看代码吧
# h" y" Q: e. B
. i4 N' y4 S) I0 \( D         bResult = CreateProcessAsUser(
$ y( k8 {3 Y* B; p                 hUserTokenDup,                              // 这个参数上面已经得到/ A% {0 d9 b& c( p. n3 J
                 _T("C:\\Windows\\System32\\notepad.exe"), //执行文件的路径
6 X4 Q/ u% {) w/ e7 d                 NULL,                              // command line
- I- ]! f" i; t7 I                 NULL,              // pointer to process SECURITY_ATTRIBUTES
- V. w3 @! x/ w  `  |                 NULL,              // pointer to thread SECURITY_ATTRIBUTES
( D8 j' K* M% S* z0 B- j$ Z                 FALSE,             // handles are not inheritable: |6 u* j/ ~; e
                 dwCreationFlags, // creation flags
# `5 S( j6 [$ u3 g                 pEnv,              // pointer to new environment block
  W/ V' ~$ M, k$ [0 ?                 NULL,              // name of current directory
  y6 a% g) Z+ N. C2 x% R                 &si,               // pointer to STARTUPINFO structure2 @/ d, C% O  V4 x
                 &pi                // receives information about new process
7 Z# q$ G2 T- b% r' n* U                 );
; w& b. {/ A6 n8 d8 J* u 2 E) }" {' B. X$ Z- O
6 @( q% l7 x: o3 g
最后大家别忘了把打开的句柄关闭。这样看起来是不是就有点简单了,其实也没什么,剩下的就是Winodws 服务的基本框架的一些东西,那些就简单了。 以上都是自己根据MSDN理解得来的,如有什么问题欢迎大家指正!
, c+ }! o; V* p9 [- t
. s) ^$ @8 \9 y% k附上Demo下载地址:http://download.csdn.net/source/3497793
发表于 2011-8-8 16:28:59 | 显示全部楼层
不錯。。。我前兩個月給OEM做的出貨用的GSensor Protect AP就是這個做法
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-10 01:28 , Processed in 0.032032 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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