2011-08-18 13 views
6

Cách tốt nhất để thêm các mục vào cửa sổ phương thức của ứng dụng khác là gì?Cách tốt nhất để thêm các mục vào cửa sổ phương thức của một ứng dụng khác là gì?

Ví dụ đơn giản mà tôi đã viết cho điều này (như một bằng chứng khái niệm) sử dụng một phương pháp mà tôi nghi ngờ nhiều, xử lý quá nhiều cho một quy trình nền tầm thường nhưng tôi gặp khó khăn trong việc đưa ra giải pháp thay thế.

Ví dụ: giả sử bạn là bác sĩ điền vào cửa sổ phương thức có dữ liệu theo toa. Bạn nhập nó trong 30 ngày với 11 lần nạp và sau đó bệnh nhân nói rằng họ muốn 90 ngày với 3 lần nạp. Ứng dụng gốc (mà bạn không có quyền truy cập vào nguồn) không có chuyển đổi dễ dàng. Tôi đã viết một tiện ích nhỏ mà đồng hồ cho cửa sổ cụ thể này (sử dụng một bộ đếm thời gian và findwindow) và khi nó tìm thấy nó, làm cho chính nó có thể nhìn thấy và đặt chính nó ở một chỗ trống trên cửa sổ phương thức mục tiêu. Khi nhấn nút "30", Rx được viết trong 30 ngày với 11 lần nạp và khi nhấn nút "90", nó sẽ thực hiện những gì bạn mong đợi. Nếu cửa sổ phương thức di chuyển, các nút 30 và 90 sẽ di chuyển với nó. Trong khi công trình này, tôi lo ngại về chi phí liên quan đến việc chạy findwindow trên một bộ đếm thời gian nhiều lần.

1) có cách nào tốt hơn không? 2) Tôi có quan tâm về điều này không? 3) bạn đang cười khúc khích tại sao kluge của tôi không hiệu quả?

Cảm ơn trước - Tôi đã rất ấn tượng với những người ở đây!

+4

Điều tôi có thể nghĩ là thay thế cài đặt móc CBT toàn cầu, nhiều lỗi hơn và dễ gây rắc rối hơn, và không miễn phí nhiều tài nguyên liên quan .. Nếu bạn không bỏ phiếu quá nhanh, hẹn giờ là tốt tôi muốn nói. –

+0

@Sertac: Vậy ... bạn sẽ xem xét việc "bỏ phiếu quá nhanh" là gì? Tôi không nhận thấy sự suy giảm hiệu năng hệ thống hoặc tăng CPU (cả hai biện pháp rất thô lỗ, tôi chắc chắn) với khoảng thời gian bỏ phiếu 250ms nhưng điều này chỉ "có vẻ sai" ... Bất kỳ điều gì chậm hơn điều đó ngăn các nút không theo biểu mẫu thông suốt. –

+1

@ b-p Bạn có thể sử dụng khoảng thời gian 1s để xem (bình chọn) cho cửa sổ và khi có một chuyển đổi được tìm thấy thành 250ms để giữ cho nó trơn tru. Bằng cách này, bạn đặt thậm chí ít căng thẳng trên hệ thống khi không có cửa sổ mục tiêu hiện tại. – ain

Trả lời

1

Cách tốt nhất là ... DLL injection.

// The DLL: 
library dll_inj; 

uses 
    ShareMem, 
    System.SysUtils, 
    System.Classes, Vcl.Dialogs, 
    windows, messages; 

{$R *.res} 

var 
    hWndMain, hDemoButton, hEdit, hNewButton, hWndEnter: THandle; 
    OldWndProc: TFarProc; 
    hBtnFont: hFont; 
    Times: integer; 
    dwThreadId: DWORD; 

function NewWndProc(hWnd: hWnd; Msg: UINT; wParam: wParam; lParam: lParam) 
    : Longint; stdcall; 
begin 
    if Times = 0 then 
    begin 
    Times := Times + 1; 
    hWndMain := FindWindowEx(0, 0, 'TForm1', 'Injection test'); 
    if hWndMain = 0 then 
     OutputDebugString('hWndMain is 0!'); 

    hNewButton := CreateWindow('button', 'NewBtn', WS_CHILD or WS_VISIBLE, 20, 
     20, 100, 24, hWndMain, 2000, GetWindowLong(hWndMain, GWL_HINSTANCE), nil); 
    if hNewButton = 0 then 
     OutputDebugString('CreateWindow failed!') 
    else 
    begin 
     hWndEnter := FindWindowEx(hWndMain, 0, 'TBitBtn', 'Enter'); 
     if hWndEnter <> 0 then 
     hBtnFont := SendMessage(hWndEnter, WM_GETFONT, 0, 0); 
     if hBtnFont <> 0 then 
     SendMessage(hNewButton, WM_SETFONT, hBtnFont, 1); 
    end; 

    hDemoButton := FindWindowEx(hWndMain, 0, 'TButton', 'Demo'); 
    if hDemoButton <> 0 then 
    begin 
     if not EnableWindow(hDemoButton, true) then 
     OutputDebugString('EnableWindow failed!'); 
    end 
    else 
     OutputDebugString('hDemoButton is 0!'); 

    hEdit := FindWindowEx(hWndMain, 0, 'TEdit', 'Serial'); 
    if hEdit = 0 then 
     OutputDebugString('hEdit is 0!') 
    else if not SetWindowText(hEdit, 'You have been hacked') then 
     OutputDebugString('SetWindowText failed!'); 
    end; 

    case Msg of 
    WM_COMMAND: 
     if (hNewButton <> 0) and (DWORD(lParam) = hNewButton) then 
     MessageBox(HWND_DESKTOP, 'You pressed a new button!', 'Yay!', MB_OK) 
     else if (hWndEnter <> 0) and (DWORD(lParam) = hWndEnter) then 
     begin 
     MessageBox(HWND_DESKTOP, 'This message is not default anymore!', 
      'Override!', MB_OK); 
     Exit(0); // Suppress default event completely 
     end; 
    end; 
    Result := CallWindowProc(OldWndProc, hWnd, Msg, wParam, lParam); 
end; 

procedure EntryPoint(Reason: integer); 
begin 
    hWndMain := FindWindowEx(0, 0, 'TForm1', 'Injection test'); 
    if hWndMain = 0 then 
    begin 
    OutputDebugString('hWndMain is 0!'); 
    Exit; 
    end; 

    OldWndProc := TFarProc(SetWindowLong(hWndMain, GWL_WNDPROC, 
    LONG(@NewWndProc))); 

    MessageBox(0, 'DLL Injected', 'OK', 0); 
end; 

begin 
    CreateThread(nil, 0, @EntryPoint, nil, 0, &dwThreadId); 

end. 

// The injector: 
program exe_inj2; 

{$APPTYPE CONSOLE} 
{$R *.res} 

uses 
    System.SysUtils, windows, TLHelp32; 

Function EnumThreadProc(wnd: HWND; Var appHwnd: HWND): LongBool; stdcall; 
Var 
    buf: array [0 .. 256] of Char; 
Begin 
    Result := LongBool(1); 
    if GetClassname(wnd, buf, sizeof(buf)) > 0 then 
    If StrComp(buf, 'TApplication') = 0 Then 
    Begin 
     appHwnd := wnd; 
     Result := False; 
    End; 
End; 

Function FindApplicationWindow(forThreadID: DWORD): HWND; 
Begin 
    Result := 0; 
    EnumThreadWindows(forThreadID, @EnumThreadProc, lparam(@Result)); 
End; 

Function ProcessIDFromAppname32(appname: String): DWORD; 
{ Take only the application filename, not full path! } 
Var 
    snapshot: THandle; 
    processEntry: TProcessEntry32; 
Begin 
    Result := 0; 
    appname := UpperCase(appname); 
    snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    If snapshot <> 0 Then 
    try 
     processEntry.dwSize := sizeof(processEntry); 
     If Process32First(snapshot, processEntry) Then 
     Repeat 
      If Pos(appname, 
      UpperCase(ExtractFilename(StrPas(processEntry.szExeFile)))) > 0 Then 
      Begin 
      Result := processEntry.th32ProcessID; 
      Break; 
      End; { If } 
     Until not Process32Next(snapshot, processEntry); 
    finally 
     CloseHandle(snapshot); 
    End; { try } 
End; 

function InjectDLL(dwPID: DWORD; DLLPath: PWideChar): integer; 
var 
    dwThreadID: Cardinal; 
    hProc, hThread, hKernel: THandle; 
    BytesToWrite, BytesWritten: SIZE_T; 
    pRemoteBuffer, pLoadLibrary: Pointer; 
begin 
    if not FileExists(DLLPath) then 
    begin 
    MessageBox(0, PWideChar('File ' + DLLPath + ' does not exist'), 'Error', 0); 
    Exit(0); 
    end; 

    hProc := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_QUERY_INFORMATION or 
    PROCESS_VM_OPERATION or PROCESS_VM_WRITE or PROCESS_VM_READ, False, dwPID); 
    if hProc = 0 then 
    Exit(0); 
    try 
    BytesToWrite := sizeof(WideChar) * (Length(DLLPath) + 1); 
    pRemoteBuffer := VirtualAllocEx(hProc, nil, BytesToWrite, MEM_COMMIT, 
     PAGE_READWRITE); 
    if pRemoteBuffer = nil then 
     Exit(0); 
    try 
     if not WriteProcessMemory(hProc, pRemoteBuffer, DLLPath, BytesToWrite, 
     BytesWritten) then 
     Exit(0); 
     hKernel := GetModuleHandle('kernel32.dll'); 
     pLoadLibrary := GetProcAddress(hKernel, 'LoadLibraryW'); 
     hThread := CreateRemoteThread(hProc, nil, 0, pLoadLibrary, pRemoteBuffer, 
     0, dwThreadID); 
     try 
     WaitForSingleObject(hThread, INFINITE); 
     finally 
     CloseHandle(hThread); 
     end; 
    finally 
     VirtualFreeEx(hProc, pRemoteBuffer, 0, MEM_RELEASE); 
    end; 
    finally 
    CloseHandle(hProc); 
    end; 
    Exit(1); 
end; 

const 
    PROCESS_NAME = 'Default_project.exe'; 

begin 
    try 
    { TODO -oUser -cConsole Main : Insert code here } 
    WriteLn(PROCESS_NAME + ' PID: ' + 
     IntToSTr(ProcessIDFromAppname32(PROCESS_NAME))); 
    InjectDLL(ProcessIDFromAppname32(PROCESS_NAME), 'dll_inj.dll'); 
    ReadLn; 
    except 
    on E: Exception do 
     WriteLn(E.ClassName, ': ', E.Message); 
    end; 

end.