动态库注入方式锁分析
This commit is contained in:
parent
d40a0fdb3d
commit
1491ef3061
|
@ -57,7 +57,7 @@
|
|||
"description": "%deadlockdetect.taskDefinitions.options.cwd.description%"
|
||||
},
|
||||
"env": {
|
||||
"type": "array",
|
||||
"type": "object",
|
||||
"description": "%deadlockdetect.taskDefinitions.options.env.description%"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
import * as vscode from 'vscode';
|
||||
import * as child from 'child_process';
|
||||
import {execDetect, testPwd, prase_yaml2html} from './utils';
|
||||
import {execDetect, archs, testPwd, prase_yaml2html} from './utils';
|
||||
import { dirname, join } from 'path';
|
||||
import { kill } from 'process';
|
||||
import * as fs from 'fs';
|
||||
|
||||
type Options = {
|
||||
cwd?: string;
|
||||
env?: string[];
|
||||
env?: {
|
||||
[name: string]: any;
|
||||
};
|
||||
};
|
||||
|
||||
var isNotSupport = false;
|
||||
|
||||
const arch = archs.get(process.arch);
|
||||
const binLoader: string = join(dirname(__dirname), "detect-tools/bincheck_loader.sh");
|
||||
const hijackLib: string = join(dirname(__dirname), "detect-tools", arch? arch : "x86_64", "");
|
||||
const hijackTool: string = join(dirname(__dirname), "detect-tools", arch? arch : "x86_64", "");
|
||||
|
||||
interface DetectTaskDefinition extends vscode.TaskDefinition {
|
||||
command: string;
|
||||
|
@ -19,14 +25,15 @@ interface DetectTaskDefinition extends vscode.TaskDefinition {
|
|||
options?: Options;
|
||||
}
|
||||
|
||||
|
||||
export class DetectTaskProvider implements vscode.TaskProvider {
|
||||
static customBuildScriptType = 'deadlockdetect';
|
||||
private tasks: vscode.Task[] | undefined;
|
||||
|
||||
private sharedState: string | undefined;
|
||||
private cmd: child.ChildProcessWithoutNullStreams | undefined;
|
||||
constructor(private workspaceRoot: string, private context: vscode.ExtensionContext) { }
|
||||
constructor(private workspaceRoot: string, private context: vscode.ExtensionContext, private _isNotSupport: boolean) {
|
||||
isNotSupport = this._isNotSupport;
|
||||
}
|
||||
|
||||
public async provideTasks(): Promise<vscode.Task[]> {
|
||||
return this.getTasks();
|
||||
|
@ -47,7 +54,6 @@ export class DetectTaskProvider implements vscode.TaskProvider {
|
|||
}
|
||||
this.tasks = [];
|
||||
var option: Options = {
|
||||
env: ["程序执行所需额外环境变量:如 DISPALY=1"],
|
||||
};
|
||||
this.tasks!.push(this.getTask("被检测可执行程序", ["可执行程序参数(可选)"], option));
|
||||
return this.tasks;
|
||||
|
@ -77,16 +83,16 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
|||
onDidClose?: vscode.Event<number> = this.closeEmitter.event;
|
||||
private passwd: string | undefined;
|
||||
private checkedPid: number = 0;
|
||||
private hadChecked: boolean = false;
|
||||
constructor(private cmd: child.ChildProcessWithoutNullStreams | undefined, private context: vscode.ExtensionContext, private command: string, private args: string[], private option: Options, private getSharedState: () => string | undefined, private setSharedState: (state: string) => void) {
|
||||
}
|
||||
|
||||
open(initialDimensions: vscode.TerminalDimensions | undefined): void {
|
||||
// At this point we can start using the terminal.
|
||||
if (this.command.length) {
|
||||
let found = false;
|
||||
vscode.workspace.workspaceFolders?.forEach((value)=>{
|
||||
// value.uri.fsPath
|
||||
if(this.command[0] == '/' && !found){
|
||||
if(this.command[0] === '/' && !found){
|
||||
this.option.cwd = value.uri.fsPath;
|
||||
found = true;
|
||||
}
|
||||
|
@ -131,10 +137,35 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
|||
this.closeEmitter.fire(0);
|
||||
}
|
||||
}
|
||||
|
||||
private hijackCheck(){
|
||||
// 注入方式
|
||||
child.exec(`${hijackTool} ${this.checkedPid}`, (err, o, e)=>{
|
||||
if(o.match(/normal/)?.length){
|
||||
const webPanel = vscode.window.createWebviewPanel(
|
||||
'detectResultWebview',
|
||||
"检测结果",
|
||||
vscode.ViewColumn.One,
|
||||
{
|
||||
enableScripts: true,
|
||||
retainContextWhenHidden: true,
|
||||
}
|
||||
);
|
||||
webPanel.webview.html = prase_yaml2html(this.command, this.context.extensionPath, webPanel.webview, o);
|
||||
return;
|
||||
}
|
||||
vscode.window.showInformationMessage("未检测到相关锁信息");
|
||||
});
|
||||
}
|
||||
|
||||
close(): void {
|
||||
if(this.cmd){
|
||||
kill(this.checkedPid, 9);
|
||||
vscode.window.showWarningMessage("检测任务已退出");
|
||||
if(isNotSupport && !this.hadChecked){
|
||||
this.hadChecked = true;
|
||||
this.hijackCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,13 +173,18 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
|||
private async doExec(): Promise<void> {
|
||||
return new Promise<void>((resolve) => {
|
||||
this.writeEmitter.fire('正在检测 ...\r\n');
|
||||
this.option.env?.forEach(e =>{
|
||||
let kv = e.split('=', 2);
|
||||
if(kv.length === 2){
|
||||
process.env[kv[0]] = kv[1];
|
||||
}
|
||||
});
|
||||
if(this.option.env){
|
||||
Object.keys(this.option.env).forEach(key => {
|
||||
let value = this.option.env?.[key];
|
||||
process.env[key] = value;
|
||||
});
|
||||
}
|
||||
let hadPid = false;
|
||||
if(isNotSupport){
|
||||
// 库注入
|
||||
this.hadChecked = false;
|
||||
process.env["LD_PRELOAD"] = hijackLib;
|
||||
}
|
||||
let coption: child.SpawnOptionsWithoutStdio = {
|
||||
env: process.env
|
||||
};
|
||||
|
@ -180,6 +216,11 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
|||
if(errmsg.length){
|
||||
vscode.window.showErrorMessage(errmsg);
|
||||
}
|
||||
if(errmsg.length === 0 && isNotSupport && !this.hadChecked){
|
||||
// 注入后锁分析
|
||||
this.hadChecked = true;
|
||||
this.hijackCheck();
|
||||
}
|
||||
this.writeEmitter.fire('被检测程序已终止 ... \r\n');
|
||||
const date = new Date();
|
||||
this.setSharedState(date.toTimeString() + ' ' + date.toDateString());
|
||||
|
@ -204,6 +245,10 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
|||
if(result.length >= 4){
|
||||
hadPid = true;
|
||||
this.checkedPid = parseInt(result[3].trim());
|
||||
if(isNotSupport){
|
||||
// 注入方式
|
||||
return;
|
||||
}
|
||||
execDetect(this.passwd, result[1].trim(), this.checkedPid, (detectResult)=>{
|
||||
if(detectResult.match(/fatal/)?.length){
|
||||
kill(this.checkedPid, 9);
|
||||
|
|
|
@ -5,7 +5,7 @@ import path = require('path');
|
|||
import fs = require("fs");
|
||||
import {DetectTaskProvider} from './detectTaskProvider';
|
||||
import { homedir } from 'os';
|
||||
import {exec} from 'child_process';
|
||||
import {exec, execSync} from 'child_process';
|
||||
import {testPwd} from './utils';
|
||||
import {doLocalPidLockAnalyse} from './analysePid';
|
||||
// linux命令操作模块
|
||||
|
@ -157,13 +157,27 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
vscode.window.showWarningMessage("检测环境失败, C/C++程序锁分析插件功能受限");
|
||||
return;
|
||||
}
|
||||
exec(`grep -r "^CONFIG_BPF_EVENTS=" /boot/config-${o}`, (e1, o1, err1)=>{
|
||||
if(e1){
|
||||
vscode.window.showWarningMessage("由于内核限制, C/C++程序锁分析插件功能受限");
|
||||
return;
|
||||
var kernelOptions: string[] = [
|
||||
"CONFIG_UPROBES=y",
|
||||
"CONFIG_UPROBE_EVENTS=y",
|
||||
"CONFIG_TRACEPOINTS=y",
|
||||
"CONFIG_PERF_EVENTS=y",
|
||||
"CONFIG_BPF_EVENTS=y"
|
||||
];
|
||||
var isNotSupport = false;
|
||||
fs.readFile(`/boot/config-${o}`, 'utf8', function (err, buffer) {
|
||||
if(err){
|
||||
isNotSupport = true;
|
||||
}else{
|
||||
var str = buffer.toString();
|
||||
kernelOptions.forEach(elem=>{
|
||||
if(!str.includes(elem)){
|
||||
isNotSupport = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
const workspaceRoot = (vscode.workspace.workspaceFolders && (vscode.workspace.workspaceFolders.length > 0)) ? vscode.workspace.workspaceFolders[0].uri.fsPath : homedir();
|
||||
detectTaskProvider = vscode.tasks.registerTaskProvider(DetectTaskProvider.customBuildScriptType, new DetectTaskProvider(workspaceRoot, context));
|
||||
detectTaskProvider = vscode.tasks.registerTaskProvider(DetectTaskProvider.customBuildScriptType, new DetectTaskProvider(workspaceRoot, context, isNotSupport));
|
||||
});
|
||||
});
|
||||
context.subscriptions.push(...[disposable,disposable0]);
|
||||
|
|
|
@ -3,10 +3,11 @@ import * as vscode from 'vscode';
|
|||
import { dirname, join } from 'path';
|
||||
import * as YAML from 'yaml';
|
||||
|
||||
const archs = new Map([
|
||||
export const archs = new Map([
|
||||
["x86_64", "x86_64"],
|
||||
["x64", "x86_64"],
|
||||
["arm64", "arm64"]
|
||||
["arm64", "arm64"],
|
||||
["aarch64", "arm64"]
|
||||
]);
|
||||
|
||||
const myArch = archs.get(process.arch);
|
||||
|
|
Loading…
Reference in New Issue