閱讀743 返回首頁    go 技術社區[雲棲]


[原創]C# 與 匯編 的一次親密接觸。

廢話不講,轉入正題!

前不久,有位網友在MSN上問我:如何解除被獨占打開文件的鎖定?
雖然從ring0層可以做到更加Power的處理,但是相對繁瑣。
權衡之後,我決定在ring3層解決這個問題。經過網上的一番搜
索之後,寫了一個簡單的exe程序。後來略覺"簡陋",遂決定加上
GUI。寫win32界麵不是匯編的強項,於是決定用.Net中的C#來寫。

C#的高級語法對於數值運算、字符串、圖形界麵的處理簡單方便;
而匯編對於程序性能優化、體積精簡、低層代碼可控性又得心應手。
兩者結合使用,可以達到揚長避短的作用。和以前我用VB   +   ASM
的花哨界麵不同,這次我力圖做到界麵最精簡(當然還是有點花哨,嗬嗬)
,先做一個DEMO,由於才學C#不久,加上水平有限,可能有很多紕漏和
錯誤,以及一些還可以優化的地方,希望各位不吝指出,多謝了。

截圖:

 

 

 

 

 

 

[細節&要點]

由文件句柄得到文件的名稱,還可以用內存影射文件的方法,但有局限性。

Assembly code

    _GetFileNameByHandle proc uses esi edi ebx _handle,_hProcess,/
    _lpFileName,/
    _lpProcessName
    ;_lpstOpenFile

    local @stFI:_FileInfo,@hThread:dword

    mov eax,_handle
    mov @stFI.Handle,eax

    invoke RtlZeroMemory,addr @stFI.FInfo.FileNameW,/
    MAX_PATH * 2

    invoke CreateThread,NULL,0,addr _WorkThread,/
    addr @stFI,0,NULL
    mov @hThread,eax

    invoke WaitForSingleObject,@hThread,100

    .if eax == WAIT_TIMEOUT
    invoke TerminateThread,@hThread,0
    .endif

    invoke CloseHandle,@hThread

    invoke RtlZeroMemory,addr buf,/
    sizeof buf

    invoke GetProcessImageFileNameA,_hProcess,addr buf,/
    sizeof buf

    invoke _GetProcessShortName,addr buf

    invoke lstrcpy,_lpProcessName,addr buf

    mov eax,@stFI.FInfo.FileNameLength

    .if eax != 0
    push eax

    invoke RtlZeroMemory,addr buf,/
    sizeof buf

    pop eax
    shr eax,1

    invoke WideCharToMultiByte,CP_ACP,0,/
    addr @stFI.FInfo.FileNameW,eax,/
    addr buf,MAX_PATH,NULL,NULL

    invoke lstrcpy,_lpFileName,addr buf
    .else
    invoke lstrcpy,_lpFileName,addr szDefaultFileName
    .endif

    ret

    _GetFileNameByHandle endp


有些"文件"(實際是管道)會造成操作掛起,遂用線程處理之:

Assembly code


    _WorkThread proc _lpFileInfo
    local IoStatus:IO_STATUS_BLOCK

    assume esi:ptr _FileInfo
    mov esi,_lpFileInfo

    invoke NtQueryInformationFile,[esi].Handle,addr IoStatus,/
    addr [esi].FInfo,sizeof(_FileInfo)-sizeof(dword),/
    FileNameInformation

    assume esi:nothing
    ret

    _WorkThread endp

關於C#與匯編的接口兼容問題,取出一個結構說明:
在C#中:

C# code



    private struct _stOpenFile
    {
    public uint lpProcessName;
    public uint lpFileName;
    public uint ProcessID;
    public uint Flags;
    public uint hFile;
    public uint GrantedAccess;
    }



在   asm   中:

Assembly code



    _stOpenFile struct

    lpProcessName dd ?
    lpFileName dd ?
    ProcessID dd ?
    Flags dd ?
    hFile dd ?
    GrantedAccess dd ?
    _stOpenFile ends



在C#中調用方法:

C# code


    private void btnFind_Click(object sender, EventArgs e)
    {
    StringBuilder szTmp = new StringBuilder(256);

    string FileName, ProcessName;

    _stOpenFile stOP = new _stOpenFile();

    this.btnFind.Enabled = false;

    this.lstvewFind.Items.Clear();
    this.lstvewFind.Refresh();

    unsafe
    {
    byte[] szProcessName = new byte[256];
    byte[] szFileName = new byte[256];

    fixed (byte* lpPN = szProcessName)
    fixed (byte* lpFN = szFileName)
    {
    stOP.lpProcessName = (uint)lpPN;
    stOP.lpFileName = (uint)lpFN;

    while (EnumAllOpenFile(ref stOP) == true)
    {
    ProcessName = Encoding.Default.GetString(szProcessName).Trim('/0');
    FileName = Encoding.Default.GetString(szFileName).Trim('/0');

    if ((FileName.ToString().Length == 0) && (ProcessName.ToString().Length == 0))
    {
    Array.Clear(szProcessName, 0, 256);
    Array.Clear(szFileName, 0, 256);
    continue;
    }

    if (FileName.ToString().ToLower() == this.txtFind.Text.ToString().ToLower())
    {
    this.lstvewFind.Items.Add(ProcessName.ToString()).SubItems.AddRange(new string[] {
    FileName.ToString(),stOP.hFile.ToString(),stOP.Flags.ToString(),
    "0x"+Convert.ToString(stOP.GrantedAccess,16),stOP.ProcessID.ToString()});
    this.lstvewFind.Refresh();
    }
    else
    {
    szTmp.Remove(0, szTmp.Length);
    szTmp.Append(FileName.ToString());
    GetShortName(szTmp);
    if (szTmp.ToString().ToLower() == this.txtFind.Text.ToString().ToLower())
    {
    this.lstvewFind.Items.Add(ProcessName.ToString()).SubItems.AddRange(new string[] {
    FileName.ToString(),stOP.hFile.ToString(),stOP.Flags.ToString(),
    "0x"+Convert.ToString(stOP.GrantedAccess,16),stOP.ProcessID.ToString()});
    this.lstvewFind.Refresh();
    }
    }
    Array.Clear(szProcessName, 0, 256);
    Array.Clear(szFileName, 0, 256);
    }
    }
    }
    MessageBox.Show("Total Find " + lstvewFind.Items.Count.ToString() + " Open Files !");

    this.btnFind.Enabled = true;
    }

    上麵應該可以再大幅度優化,請各位不吝指出,多謝。




最後更新:2017-04-02 00:06:25

  上一篇:go 爆笑!正準備申請吉尼斯的BBS語錄
  下一篇:go 奇文共賞 - 評[奇文共賞 - 評:挑戰水晶報表,潤乾還不夠資格]