1. 程式人生 > >使用CBrother的CLIB庫呼叫windows的API

使用CBrother的CLIB庫呼叫windows的API

使用CBrother的CLIB庫呼叫windows的API

2.1.0版本CBrother加入了CLib庫,最新需要寫一個工具,根據路徑查殺一個Windows程序,研究了一下,CLib庫的用法,感覺還是比較靈活的。

首先我要明確每一個API在系統的哪一個dll裡面,我一般都是去微軟官網查這個API。(https://docs.microsoft.com/zh-cn/windows/win32/api/),

比如我查OpenProcess這個API,查到如下內容

 

 

 

 

 

 在Kernel32.dll裡面,其他用到的API也都是這樣獲取資訊,下面就可以寫程式碼了。

 1 import CBCLib.code
 2 
 3 var g_kernel32_init = false;                    //kernel32.dll 是否初始化
 4 var g_kernel32 = null;                          //Kernel32.dll 控制代碼
 5 var g_kernel32_OpenProcess = null;              //OpenProcess函式
 6 var g_kernel32_CloseHandle = null;              //CloseHandle函式
 7 var g_kernel32_GetModuleFileNameExA = null;     //GetModuleFileNameExA函式
 8 var g_kernel32_GetLogicalDriveStringsA = null;  //GetLogicalDriveStringsA函式
 9 var g_kernel32_QueryDosDeviceA = null;          //QueryDosDeviceA函式
10 
11 var g_psapi_init = false;                       //psapi.dll 是否初始化
12 var g_psapi = null;                             //psapi.dll 控制代碼
13 var g_psapi_GetProcessImageFileNameA = null;    //GetProcessImageFileNameA函式
14 
15 const MAX_PATH = 1024;
16 
17 //獲取kernel32.dll裡面的函式
18 function initkernel32()
19 {
20     if (g_kernel32_init)
21     {
22         return;
23     }
24 
25     g_kernel32_init = true;
26 
27     g_kernel32 = new CLib("kernel32.dll");          
28     if(!g_kernel32.load())
29     {
30         print "kernel32.dll load err!";
31         return;
32     }
33 
34     //根據函式原型和CLib庫型別對應關係寫引數列表
35     g_kernel32_OpenProcess = g_kernel32.findFunc("OpenProcess","pointer","int","bool","int");
36     g_kernel32_CloseHandle = g_kernel32.findFunc("CloseHandle","bool","int");
37     g_kernel32_GetModuleFileNameExA = g_kernel32.findFunc("K32GetModuleFileNameExA","int","pointer","pointer","pointer","int");
38     g_kernel32_GetLogicalDriveStringsA = g_kernel32.findFunc("GetLogicalDriveStringsA","int","int","pointer");
39     g_kernel32_QueryDosDeviceA = g_kernel32.findFunc("QueryDosDeviceA","int","string","pointer","int");
40 }

我還用到了psapi.dll裡面的函式

 1 //Psapi.dll裡面的函式
 2 function initpsapi()
 3 {
 4     if (g_psapi_init)
 5     {
 6         return;
 7     }
 8     g_psapi_init = true;
 9 
10     g_psapi = new CLib("Psapi.dll");
11     if (!g_psapi.load())
12     {
13         print "Psapi.dll load err!";
14         return;        
15     }
16 
17     //根據函式原型和CLib庫型別對應關係寫引數列表
18     g_psapi_GetProcessImageFileNameA = g_psapi.findFunc("GetProcessImageFileNameA","int","pointer","pointer","int");
19 }

下面是根據程序pid獲取程序路徑

 1 const STANDARD_RIGHTS_REQUIRED = 0x000F0000;
 2 const SYNCHRONIZE = 0x00100000;
 3 function GetProcessPath(pid)
 4 {
 5     initkernel32();
 6 
 7     //開啟目標程序
 8     var hProcess = g_kernel32_OpenProcess.callFunc(STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF,false,pid);
 9     if (hProcess.isNull())
10     {
11         print "openprocess err! " + pid;
12         return;        
13     }
14 
15     //構建一個buffer,GetModuleFileNameExA會把路徑寫進這個buffer裡
16     var pathBuff = new CLibPointer();
17     pathBuff.malloc(MAX_PATH);
18 
19     var res = g_kernel32_GetModuleFileNameExA.callFunc(hProcess,null,pathBuff,MAX_PATH);
20     if(res > 0)
21     {
22         //GetModuleFileNameExA獲取成功
23         res = pathBuff.readString();
24     }
25     else
26     {
27         //有些系統獲取不成功,需要使用另外一種方法。32位程式獲取64位程序也需要用這種方法。
28         res = GetProcessPathByPsapi(hProcess);
29     }
30 
31     //釋放buffer
32     pathBuff.free();
33 
34     //關閉目標程序控制代碼
35     g_kernel32_CloseHandle.callFunc(hProcess);
36     return res;
37 }

如果GetModuleFileNameExA獲取失敗了,需要使用GetProcessImageFileNameA獲取dos路徑,然後轉化成絕對路徑

 1 //使用GetProcessImageFileNameA獲取程序路徑
 2 function GetProcessPathByPsapi(hProcess)
 3 {
 4     initkernel32();
 5     initpsapi();
 6 
 7     var newPath = "";
 8     var tempBuff = new CLibPointer();
 9     tempBuff.malloc(MAX_PATH);
10     var res = g_psapi_GetProcessImageFileNameA.callFunc(hProcess,tempBuff,MAX_PATH);
11     if(res > 0)
12     {
13         var driveStr = new CLibPointer();
14         driveStr.malloc(MAX_PATH);
15         //獲取所有碟符
16         if(g_kernel32_GetLogicalDriveStringsA.callFunc(MAX_PATH,driveStr))
17         {
18             var dospath = tempBuff.readString();
19             var driveName = new CLibPointer();
20             driveName.malloc(MAX_PATH);
21             var copydriveStr = driveStr.copyAddr();
22 
23             //遍歷碟符,和DOS碟符名稱對照
24             while (1)
25             {
26                 var szDrive = copydriveStr.readString();
27                 szDrive = strget(szDrive,0,2);
28                 if(g_kernel32_QueryDosDeviceA.callFunc(szDrive,driveName,MAX_PATH))
29                 {
30                     var dname = driveName.readString();
31                     var namelen = strlen(dname);                 
32                     if(strnicmp(dname,dospath,namelen) == 0)
33                     {
34                         //對上了,說明就是這個路徑
35                         newPath = szDrive;
36                         newPath += strget(dospath,namelen);
37                         break;
38                     }
39                     
40                     //碟符指標向前加4獲取下一個碟符
41                     copydriveStr.addAddr(4);                    
42                 }
43                 else
44                 {
45                     break;
46                 }                  
47             }
48 
49             driveName.free();
50         }
51         driveStr.free();
52     }
53 
54     tempBuff.free();
55     return newPath;
56 }

下面就是在main函式使用

 1 var g_path = "E:\\111\\test.exe";       //程序路徑
 2 var g_name = "test.exe";                //程序名
 3 function main(params)
 4 {
 5     //這個函式是CBrother提供的,根據程序名獲取pid,存到array裡
 6     var pidarr = GetProcessByName(g_name);
 7     for (var i = 0; i < pidarr.size() ; i++)
 8     {
 9         //根據pid獲取程序路徑
10         var path = GetProcessPath(pidarr[i]);
11         if (path == g_path)
12         {
13             //如果路徑匹配上了,殺掉。這個函式也是CBrother提供的,根據程序ID查殺程序
14             KillProcessByID(pidarr[i]);
15         }        
16     }
17 }

用法還是比較容易理解,只要你熟悉windows程式設計,那麼CBrother可以做任意你想做的事情。

上面這個api的用法我已經把程式碼發給作者了,作者說後續會加入lib庫裡,後續慢慢擴充套件成所有的api,這樣在windows下使用api的就更方便