జ్ఞ ా رً ॣ
腳本是什么應該就不用多說了吧,想必想寫腳本的人一定知道什么是腳本;
眾所周知,c++不是寫腳本的最佳選擇;但我最熟悉c++,所以一直在用它寫腳本,偶爾用html5寫寫github的網頁,js什么的就靠其他大神的成就啦~。
接下來介紹c++的基本用法;
一、鼠標的控制:
正如小數有double,整數有int,鼠標也有自己的定義:POINT;
POINT p; //我們定義了一個名字叫做p的鼠標;
那么靠這個p可以做什么呢?
1.有時候為了控制鼠標,我們需要知道屏幕某個點的坐標:
p是封裝的,也就是說可以調用p.x和p.y,即:
cout<<p.x<<" "<<p.y<<endl; //輸出的便是鼠標在屏幕上的坐標;
但是,定義p之后直接調用p.x和p.y是不行的,因為你沒有給p賦值。因此調用:
GetCursorPos(&P); //坐標便是目前鼠標的位置,以屏幕的左上角為(0,0)的平面直角坐標系,右下角便是你屏幕的分辨率最大值;大小寫要注意,一定不能寫錯;
有人測試后會發現,我僅僅是讀到了一瞬間的鼠標位置,難道每測一次都要運行一次嗎?
算法的基礎去哪了?while大循環啊!
#include <bits/stdc++.h>
#include <windows.h>
#define inc(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
int main()
{
POINT P;
while(1){
GetCursorPos(&P);
printf("%d %d \r",P.x,P.y);
}
}
請注意,腳本處處是坑,prinf("\r")的用法是接下來輸出的內容從這一行開始輸出,可以覆蓋原來的內容;如果沒被覆蓋完全那么沒被覆蓋的部分就仍然保持原來的內容;
也就是說:printf("%d %d\r",P.x,P.y);是不行的,只能printf("%d %d \r",P.x,P.y);
為什么呢?如果原來的坐標是(123,1024); 即輸出:123 1024;
假如你移動你的指針到(21,35);那么是輸出21 35嗎?不是,輸出的是21 35024;原因參考\r的用法,自己體會吧;
2.我們需要把鼠標移到某個位置,並單擊或雙擊
首先你需要先知道屏幕的分辨率最大是什么:
int x=GetSystemMetrics(SM_CXSCREEN); int y=GetSystemMetrics(SM_CYSCREEN);
現在(x,y)就是右下角的坐標;
與GetCursorPos相對的,SetCursorPos(x,y)是將鼠標移到屏幕上坐標是(x,y)的位置上。如:SetCursorPos(264,119);
模擬鼠標的點擊:
mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0); //模擬按下鼠標左鍵 mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0); //模擬抬起鼠標左鍵
但要注意,按下抬起兩次中間要給電腦運行提供一個時間,這時需要用到:Sleep()函數;如Sleep(2234)就是程序暫停2234毫秒;
因此寫出函數:
void click(){ //模擬了鼠標的單擊 mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0); Sleep(100); mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0); }
那么雙擊呢?想必可以自己寫出來了吧;就是調用兩次click();
二、鍵盤的控制
僅僅依靠鼠標無法寫出好的腳本,因此鍵盤的控制也不能少;
1.監測鍵盤的按鍵
比如說你寫了這樣一個腳本,用來惡搞同學:
int x=GetSystemMetrics(SM_CXSCREEN);
int y=GetSystemMetrics(SM_CYSCREEN);
while(1){ SetCursorPos(rand()%x,rand()%y);
Sleep(200);
}
顯然的,惡搞結束后就算是你想停止該程序運行也只能使用鍵盤win+r運行cmd,通過tasklist和taskkill /pid來結束進程;
那么有沒有更好的辦法呢?
有!就像俠盜獵車手GTA的秘籍差不多,按下指定的按鍵組合后停止該程序;
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
上面這句話就是把寫起來賊為困難的話變成人話,這個函數的返回值是一個bool值,如果按下了VK_NONAME鍵,返回1,否則返回0;
因此可以將惡搞的程序修改一下:
int x=GetSystemMetrics(SM_CXSCREEN); int y=GetSystemMetrics(SM_CYSCREEN); while(1){ SetCursorPos(rand()%x,rand()%y); Sleep(200); if(KEY_DOWN(‘M')&&KEY_DOWN('X')&&KEY_DOWN('R')){ return 0; } }
這樣你只需要像真正的大佬一樣,隨意的按下幾個鍵子,就終止了這個看似惡魔般的程序;
2.模擬鍵盤的按鍵
先來看一下這兩個函數:
keybd_event(ascii,0,0,0); keybd_event(ascii,0,KEYEVENTF_KEYUP,0);
第一個參數:虛擬鍵碼(鍵盤鍵碼對照表一會給出);
第二個參數:硬件掃描碼,一般設置為0即可;
第三個參數:函數操作的一個標志位,如果值為KEYEVENTF_EXTENDEDKEY則該鍵被按下,也可設置為0即可,如果值為KEYEVENTF_KEYUP則該按鍵被抬起;
第四個參數:定義與擊鍵相關的附加的32位值,一般設置為0即可。
其中要格外注意,ascii並不是傳統的ASCII碼,
因此可以寫出模擬按下按鍵的函數:
void press(int asi){ keybd_event(asi,0,0,0); keybd_event(asi,0,KEYEVENTF_KEYUP,0); Sleep(100); }
三、獲取系統信息優化腳本
很多時候,為了得到某些數據,我們需要從電腦中讀取或運行某些東西,所以需要更多的腳本技巧;
1.獲取系統目前的時間
time_t nowTime = time(NULL); struct tm *t = localtime(&nowTime); printf("\r%d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
time_t 是一種類型,它定義的是時間類型nowTime;
結構體指tm針指向的是nowTime的地址;
tm結構體的原型:
struct tm { int tm_sec; /* 秒,范圍從 0 到 59 */ int tm_min; /* 分,范圍從 0 到 59 */ int tm_hour; /* 小時,范圍從 0 到 23 */ int tm_mday; /* 一月中的第幾天,范圍從 1 到 31 */ int tm_mon; /* 月份,范圍從 0 到 11 */ int tm_year; /* 自 1900 起的年數 */ int tm_wday; /* 一周中的第幾天,范圍從 0 到 6 */ int tm_yday; /* 一年中的第幾天,范圍從 0 到 365 */ int tm_isdst; /* 夏令時 */ };
localtime(&nowTime);把從1900-1-1零點零分到當前時間系統所偏移的秒數時間轉換為本地時間;
%02d指的就是如果位數不夠就補0補到2位;
如數字是0,那么輸出00;
2.設置程序的正版激活信息
眾所周知,每台電腦乃至每個主板、硬盤都有唯一的編號,我們在激活時使用這些編號作為hash值,並生成針對於此hash值下的激活代碼。(比如說用后綴自動機或者回文自動機算法來得到一個10MB的序列)這樣就算其他終端得到這台終端的激活碼也無法使用軟件。
我們可以用三種語句來獲得唯一號:
wmic BaseBoard get Manufacturer wmic BaseBoard get Product wmic diskdrive get SerialNumber //硬盤唯一號
我通常選用第三句獲取硬盤信息;
請注意,這三句話並不是c++的語言,而是cmd中的語法;
在c++中,對於調用的cmd語法,我們可以使用system(".........");這樣的語句。比如說system("ping baidu.com -l 1024 -t"); 或者system("wmic diskdrive get SerialNumber");
對於cmd中的語法,下面或許會有一些專項介紹;
但是,僅僅運行system("wmic diskdrive get SerialNumber");僅僅會在控制台上得到結果,無法讓程序得到有效輸入,怎么辦呢?
解決辦法之一:將這句話運行時重定向輸出內容到一個文件比如tmp.out,然后程序再重定向輸入到tmp.out中;
解決方法之二:重定向輸入到控制台,讀取控制台顯示的內容;
void GetOnlykey(){ //第二種解決問題的辦法 FILE *popen(const char *command,const char *type); FILE *file; strcat(ptr, "wmic diskdrive get SerialNumber"); if((file=_popen(ptr, "r"))!=NULL) { while(fgets(tmpp,1024,file)!=NULL){ memcpy(tmp,cmd,1024); memcpy(cmd,tmpp,1024); //只需要最后一行的字符串 } _pclose(file); } inc(i,1,(int)strlen(tmp)) onlykey=(onlykey*10%p+tmp[i])%p; }
在這里稍微擴展一下,freopen("tmp.in","r",stdin);將輸入流定義到tmp.in文件里,而freopen("con","r",stdin);將輸入流定義到控制台了;
獲得hash之后作為種子,srand("hash值")就好了;
3.設定該程序后台運行;
要做到這種效果,我們需要用到除了c++之外的語言。即:.vbs文件
我們新建一個文檔,鍵入以下內容,並把擴展名更改為.vbs;
Set us=WScript.CreateObject("WScript.shell") us.Run "solve.exe" ,0
其中“us”是一個名稱,可以隨意設定; "solve.exe"是要后台運行程序的名稱;這兩個地方可以根據需要進行修改;
假設這個.vbs文件叫background.vbs。那么如何在c++的程序中調用它呢?
使用cmd中start的語法,調用語句:system("start background.vbs");就可以了。但要注意,vbs文件和該c++程序需要在一個文件夾內,否則應該使用cmd的start擴展語法;(具體的在cmd語法介紹里);
四、cmd——命令提示符語法簡介
之前便說過,在c++中調用cmd的語法需要用到system(".......");語句,而要調用system(" "),我們需要包含<windows.h>庫,也就是#include <windows.h>
1.cd語法:
cd命令是”change directory”中單詞的首字母縮寫,其英文釋義是改變目錄,所以該命令的功能是從當前目錄切換到指定目錄。
其中目錄的路徑可分為絕對路徑和相對路徑。若目錄名稱省略,則切換至使用者的用戶目錄(也就是剛登錄時所在的目錄、home目錄)。
用法:cd [選項] [目錄名]
cd / 切換到用戶根目錄
cd ../.. 返回上兩級目錄;
cd .. 表示切換到上一級目錄。
cd !$ 把上個命令的參數作為cd參數使用。
2.dir語法:
/S 顯示指定目錄和所有子目錄中的文件。
dir /? 顯示目錄中的文件和子目錄列表。
dir /d 只顯示當前目錄下的文件名稱
dir /od 按文件修改時間排序,遞增;
dir /o-d 按文件修改時間排序,遞減
dir /od/tc 按文件創建時間排序,遞增
dir /o-d/tc 按文件創建時間排序,遞減
dir /on 按文件名排序對應,遞增
dir /o-n 按文件名排序對應,遞減
dir /oe 按擴展名排序對應,遞增
dir /o-e 按文件名排序對應,遞減
dir /s /b >a.txt 打印文件夾下的所有文件
3.title語法:
title ...... 其中“......”便是程序的標題;
4.start語法:
利用好start語法可以干很多事情呦,比如說運行電腦中某個位置的程序,或者打開某個網頁;
比如打開baidu.com: system("start https://www.baidu.com");
比如運行位於C:\Users\Administrator\Desktop上的1.exe,那么我們system("start C:\\Users\\Administrator\\Desktop\\1.exe");
注意,單斜杠要變成雙斜杠,否則系統會認為這是個亂糟糟的轉義序列;
5.下載http文件
win10中有個powershell可以實現此功能
powershell的兩種打開方式:直接在開始菜單里找或者在cmd中輸入start powershell回車就可以啟動
打開powershell后輸入:
$client = new-object System.Net.WebClient $client.DownloadFile('#1', '#2')
其中#1填寫下載地址,#2填寫本地保存位置,例如:
$client = new-object System.Net.WebClient
$client.DownloadFile('http://static.duoshuo.com/embed.js','d:\embed.js')