Monday, 18 October 2010

Killing suspicious processes

As a result of an experiment, we found out that one process was being run in my local machine by an unknown user and this trigger my curiosity to know more about this and which actions I could do to fix it. Firstly, I decided to monitor the process and gather data from it by using some Delphi API libraries and secondly, build a little application to kill the process and keep a little log just in case. The application is called Thundax Suspicious process watcher v1.1 and it's able to filter processes by unknown/known users and apply actions to them.
Once the application is found (by the process to inspect text box) the utility kills the process and shows the resulted information. We can also force the killing system to the known processes and use it to force the end of and application by filtering it by name and user name.
In the next picture you can notice that I've terminated the execution of the notepad.exe by simply adding it name and process user name (me).
The application core is based on two parts, the first one that is able to search for the applications that are being run in your machine and the second one that is able to kill a process by its PID. Here you can get the implemented code:

Get process list:
procedure ProcessList();
var
    hProcSnap: THandle;
    pe32: TProcessEntry32;
    Domain, User: string;
    listItem: TListItem;
begin
    hProcSnap := CreateToolHelp32SnapShot(TH32CS_SNAPALL, 0);
    if hProcSnap = INVALID_HANDLE_VALUE then
        Exit;
    pe32.dwSize := Sizeof(ProcessEntry32);
    ListView1.Clear;
    listCompare.List1.Clear;
    if Process32First(hProcSnap, pe32) = True then
        while Process32Next(hProcSnap, pe32) = True do
        begin
            if GetUserAndDomainFromPID(pe32.th32ProcessID, User, Domain) then
            begin
                if RadioButton2.Checked then
                begin
                    listItem := ListView1.Items.Add;
                    listItem.Caption := pe32.szExeFile;
                    listItem.SubItems.Add(IntToStr(pe32.th32ProcessID));
                    listItem.SubItems.Add(User);
                    listItem.SubItems.Add(Domain);
                    listCompare.List1.Add(pe32.szExeFile);
                    if AnsiUpperCase(pe32.szExeFile) = AnsiUpperCase(Edit2.text) then
                    begin
                        if Edit3.text <> '' then
                        begin
                            if AnsiUpperCase(User) = AnsiUpperCase(Edit3.text) then
                            begin
                                Log('Application founded ->' + AnsiUpperCase(Edit2.text));
                                if CheckBox3.Checked then
                                begin
                                    KillProcess(pe32.th32ProcessID);
                                    Sleep(300);
                                    Log('Application killed ->' + AnsiUpperCase(Edit2.text));
                                end
                            end;
                        end
                        else
                        begin
                            Log('Application founded ->' + AnsiUpperCase(Edit2.text));
                            if CheckBox3.Checked then
                            begin
                                KillProcess(pe32.th32ProcessID);
                                Sleep(300);
                                Log('Application killed ->' + AnsiUpperCase(Edit2.text));
                            end
                        end;

                    end;
                end
            end
            else
            begin
                if RadioButton1.Checked then
                begin
                    // Suspicious Items
                    listItem := ListView1.Items.Add;
                    listItem.Caption := pe32.szExeFile;
                    listItem.SubItems.Add(IntToStr(pe32.th32ProcessID));
                    listItem.SubItems.Add('UNKNOW');
                    listItem.SubItems.Add('UNKNOW');
                    listCompare.List1.Add(pe32.szExeFile);
                    if AnsiUpperCase(pe32.szExeFile) = AnsiUpperCase(Edit1.text) then
                    begin
                        Log('Application founded ->' + AnsiUpperCase(Edit1.text));
                        if CheckBox2.Checked then
                        begin
                            KillProcess(pe32.th32ProcessID);
                            Sleep(300);
                            Log('Application killed ->' + AnsiUpperCase(Edit1.text));
                        end
                    end;
                end
            end;
            Application.ProcessMessages;
        end;
    CloseHandle(hProcSnap);
end;

function GetUserAndDomainFromPID(ProcessId: DWORD; var User, Domain: string): Boolean;
var
    hToken: THandle;
    cbBuf: Cardinal;
    ptiUser: PTOKEN_USER;
    snu: SID_NAME_USE;
    ProcessHandle: THandle;
    UserSize, DomainSize: DWORD;
    bSuccess: Boolean;
begin
    Result := false;
    ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION, false, ProcessId);
    if ProcessHandle <> 0 then
    begin
        if OpenProcessToken(ProcessHandle, TOKEN_QUERY, hToken) then
        begin
            bSuccess := GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf);
            ptiUser := nil;
            while (not bSuccess) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) do
            begin
                ReallocMem(ptiUser, cbBuf);
                bSuccess := GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf);
            end;
            CloseHandle(hToken);

            if not bSuccess then
            begin
                Exit;
            end;

            UserSize := 0;
            DomainSize := 0;
            LookupAccountSid(nil, ptiUser.User.Sid, nil, UserSize, nil, DomainSize, snu);
            if (UserSize <> 0) and (DomainSize <> 0) then
            begin
                SetLength(User, UserSize);
                SetLength(Domain, DomainSize);
                if LookupAccountSid(nil, ptiUser.User.Sid, PChar(User), UserSize, PChar(Domain), DomainSize, snu) then
                begin
                    Result := True;
                    User := StrPas(PChar(User));
                    Domain := StrPas(PChar(Domain));
                end;
            end;

            if bSuccess then
            begin
                FreeMem(ptiUser);
            end;
        end;
        CloseHandle(ProcessHandle);
    end;
end;

Kill process by PID:
procedure KillProcess(pid: integer);
var
    h: THandle;
begin
    try
        h := OpenProcess(PROCESS_TERMINATE, false, pid);
        try
            if h <> 0 then
                TerminateProcess(h, 0);
        finally
            CloseHandle(h);
        end;
    except
        ShowMessage('Error');
    end;
end;

Let me know if you have any doubt about the program or any improvement!.

Related links:

0 comments:

Post a Comment