学生机房管理助手 分析和破解

Update 2022-1-30

今天看到这软件更新了7.1版本,然后又被以前那个程序破解了。

属实是更新了个寂寞。

如果你只想要破解程序就点我 密码:55oe

前言

道高一尺,魔高一百丈 ——xys

前几天上信息课时,插入U盘,然后…

jfglzs-USB

???什么阴间玩意

重启电脑后发现是初中部机房新装的一个软件,叫"学生机房管理助手"。

jfglzs-main

一看官网,“保护26种电子教室” “禁止学生10种常见脱控方法”,专门防止学生脱离控制的。

还附赠了个特别阴间的视频:

无法容忍禁用USB,遂尝试破解之。

分析

安装

刚到家就在虚拟机里安装了一份来以身试毒。

设置极域主程序后,只要对极域有任何操作(包括但不限于结束进程、冻结进程、DLL注入等)都会造成蓝屏,只能重启。

在网上搜索这个东西的资料,发现做了混淆,无法破解密码,可以考虑直接吔掉主程序。

研究

分析进程 - jfglzs.exe

"学生机房管理助手"在安装后会禁用任务管理器、CMD、“运行”、和注册表编辑器。

使用工具解除了任务管理器限制,发现有可疑进程 jfglzs.exe,显然就是这玩意的主程序。

jfglzs-taskmgr

但是当我把jfglzs.exe关掉的时候,又蓝屏了,显然有双进程保护。

jfglzs-error

双进程保护

程序使用两个进程互相保护的行为。例如程序AB进行保护,互相检测对方进程是否存在,如果你将A结束B就会将A再启动,反之同理。

分析进程 - 2

打开jfglzs.exeexe位置…

jfglzs-files

jfglzs.exe不用说;main.exe经测试是这东西的UI面板。

就是这个东西

srvany.exe似乎是一个辅助程序,用途不明。

最有意思的是pfn.exeprozs.exe

pfn.exe显然就是机房管理助手的保护进程,但如果试图把它关掉也会蓝屏。

而当我运行prozs.exe时发现没有效果,给它拖到了桌面上,发现每次点开就会生成并运行一个新的pfn.exe…而且这个新生成文件的文件名和日期有关,是随机的。

jfglzs-prozs

破解方式

分析完成。我们可以得出结论,只需要把以上提到的全部exe都破坏即可关闭机房管理助手。

问题在于prozs.exe随机生成的保护程序,这样便无法根据进程名找到进程。

但是这些全部的exe文件都位于机房管理助手的安装目录(C:\中的一个随机名称目录),prozs.exe生成的保护程序也不例外,因此我们只需要获得jfglzs.exe(只要机房管理助手开启这个进程是一定存在的)的exe位置(即机房管理助手的安装目录)并控制所有exe位置在安装目录的进程即可。

代码实现

先写出获取进程路径的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
BOOL dos2nt(LPTSTR pszDosPath, LPTSTR pszNtPath) {
TCHAR szDriveStr[500];
TCHAR szDrive[3];
TCHAR szDevName[100];
INT cchDevName;
INT i;
if(!pszDosPath || !pszNtPath )
return FALSE;
if(GetLogicalDriveStrings(sizeof(szDriveStr), szDriveStr)) {
for(i = 0; szDriveStr[i]; i += 4) {
if(!lstrcmpi(&(szDriveStr[i]), TEXT("A:\\")) || !lstrcmpi(&(szDriveStr[i]), TEXT("B:\\"))) {
continue;
}
szDrive[0] = szDriveStr[i];
szDrive[1] = szDriveStr[i + 1];
szDrive[2] = '\0';
if(!QueryDosDevice(szDrive, szDevName, 100)) {
return FALSE;
}
cchDevName = lstrlen(szDevName);
if(_tcsnicmp(pszDosPath, szDevName, cchDevName) == 0) {
lstrcpy(pszNtPath, szDrive);
lstrcat(pszNtPath, pszDosPath + cchDevName);
return TRUE;
}
}
}
lstrcpy(pszNtPath, pszDosPath);
return FALSE;
}
std::string get_path(DWORD dwPID) {//根据PID获取进程路径
TCHAR szImagePath[MAX_PATH];
TCHAR pszFullPath[MAX_PATH];
HANDLE hProcess;
std::string fullPath = "NULL";
if(!pszFullPath) {
return fullPath;
}
pszFullPath[0] = '\0';
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, dwPID);
if(!hProcess) {
return fullPath;
}
if(!GetProcessImageFileName(hProcess,szImagePath,MAX_PATH)) {
CloseHandle(hProcess);
return fullPath;
}
if(!dos2nt(szImagePath, pszFullPath)) {
CloseHandle(hProcess);
return fullPath;
}
CloseHandle(hProcess);
fullPath = pszFullPath;
return fullPath;
}

再写出查找与冻结进程的代码:

为了防止触发双进程保护,我们使用冻结进程代替结束进程。

可以把这里的冻结进程函数用在一个正常的进程上测试冻结进程的效果。

这里有一个简单实用的测试程序。

1
2
3
4
5
6
7
#include <Windows.h>
#include <iostream>
int cnt = 0;
int main(){
while(1) std::cout << ++cnt << std::endl,Sleep(200);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
inline PROCESSENTRY32 find_process(std::string name) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pi, nul;
nul.th32ProcessID = 0;
if (INVALID_HANDLE_VALUE == hSnapshot) return pi;
pi.dwSize = sizeof(PROCESSENTRY32);
BOOL bRet = Process32First(hSnapshot, &pi);
while (bRet) {
if(stricmp(pi.szExeFile, name.c_str()) == 0) return pi;
bRet = Process32Next(hSnapshot, &pi);
}
return nul;
}
inline int get_pid(std::string name){//根据进程名获取PID
return find_process(name).th32ProcessID;
}
inline void suspend_process(int pid) {//根据PID冻结进程
THREADENTRY32 th32;
th32.dwSize = sizeof(th32);
HANDLE hThreadSnap =::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if(hThreadSnap == INVALID_HANDLE_VALUE) return;
BOOL bRet =::Thread32First(hThreadSnap, &th32);
while(bRet) {
if(th32.th32OwnerProcessID == pid) {
HANDLE oth = OpenThread(THREAD_ALL_ACCESS, FALSE, th32.th32ThreadID);
::SuspendThread(oth);
CloseHandle(oth);
break;
}
bRet = ::Thread32Next(hThreadSnap, &th32);
}
::CloseHandle(hThreadSnap);
}

还需要一个函数获取全部的进程列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
inline std::vector<PROCESSENTRY32> process_list() {
std::vector<PROCESSENTRY32> process;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot) return process;
PROCESSENTRY32 pi;
pi.dwSize = sizeof(PROCESSENTRY32);
BOOL bRet = Process32First(hSnapshot, &pi);
while (bRet) {
process.push_back(pi);
bRet = Process32Next(hSnapshot, &pi);
}
return process;
}

最后简单的写一个暴力主程序即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
inline void work() {
//可以忽略color()函数 只是用于调整输出颜色 没有实际作用
cout << color(color::white) << "[!] F*cking jfglzs..." << endl;
int proc = sys::process::get_pid(main_file);//获得jfglzs.exe PID
if(!proc) {
cout << color(color::red) << "[!] ERROR: jfglzs.exe is not running." << endl;
color::clear();
return;
}
string path = sys::process::get_path(proc);//获得进程路径
path.erase(path.begin()+path.find_last_of('\\'),path.end());//获得安装目录
cout << color(color::white) << "[+] jfglzs.exe is in " << path << '.' << endl;
cout << color(color::white) << "[!] Traverse process:" << endl;
auto vec = sys::process::process_list();//遍历进程
for(auto elm:vec) {
cout << color(color::white) << "[-] Scanning process: " << color(color::blue) << elm.szExeFile << " pid=" << elm.th32ProcessID << endl;
if(!elm.th32ProcessID) continue;
string str = sys::process::get_path(elm.th32ProcessID);
if(str.size()&&str.find(path)!=string::npos) {//如果当前遍历的进程路径中含有机房管理助手安装目录
cout << color(color::green) << "[!] Suspend process: " << elm.szExeFile << " pid=" << elm.th32ProcessID << endl;
sys::process::suspend_process(elm.th32ProcessID);//冻结进程!
}
}
cout << color(color::green) << "[!] Crack complete." << endl;
color::clear();
}
//编译选项 -lpsapi

别忘了解除任务管理器、CMD等的禁用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
inline bool CreateReg(HKEY Root,char*szSubKey,char* ValueName,char* Data) {
HKEY key;
long Ret=RegCreateKeyEx(Root,szSubKey,0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&key,NULL);
Ret=RegSetValueEx(key,ValueName,0,REG_SZ,(BYTE*)Data,strlen(Data));
if(Ret!=ERROR_SUCCESS) return true;
RegCloseKey(key);
return false;
}
inline void regfix() {
cout << color(color::white) << "[!] Fixing register..." << endl;
char val[32] = {0};
if(CreateReg(HKEY_CURRENT_USER,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System","DisableTaskMgr",val)==ERROR_SUCCESS)
cout << color(color::green) << "[+] taskmgr.exe fixed." << endl;
else cout << color(color::red) << "[-] Fix taskmgr.exe failed." << endl;
if(CreateReg(HKEY_CURRENT_USER,"SOFTWARE\\Policies\\Microsoft\\Windows\\System","DisableCMD",val)==ERROR_SUCCESS)
cout << color(color::green) << "[+] cmd.exe fixed." << endl;
else cout << color(color::red) << "[-] Fix cmd.exe failed." << endl;
if(CreateReg(HKEY_CURRENT_USER,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System","DisableRegistryTools",val)==ERROR_SUCCESS)
cout << color(color::green) << "[+] regedit.exe fixed." << endl;
else cout << color(color::red) << "[-] Fix regedit.exe failed." << endl;
if(CreateReg(HKEY_CURRENT_USER,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\EXPLORER","RESTRICTRUN",val)==ERROR_SUCCESS)
cout << color(color::green) << "[+] gpedit.msc fixed." << endl;
else cout << color(color::red) << "[-] Fix gpedit.msc failed." << endl;
if(CreateReg(HKEY_CURRENT_USER,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\EXPLORER","NoRun",val)==ERROR_SUCCESS)
cout << color(color::green) << "[+] \"Run\" fixed." << endl;
else cout << color(color::red) << "[-] Fix \"Run\" failed." << endl;
color::clear();
}

jfglzs-crack

Enjoy!

破解程序下载

蓝奏云 密码:55oe


学生机房管理助手 分析和破解
https://www.d0j1a1701.cc/p/91e17a8a/
作者
d0j1a_1701
发布于
2021年12月11日
许可协议
CC-BY-SA