1. 程式人生 > 其它 >羽夏逆向破解日記簿——資料夾加密大師的逆向分析

羽夏逆向破解日記簿——資料夾加密大師的逆向分析

羽夏逆向破解日記簿之某版本的資料夾加密大師的逆向分析

前言

  資料夾加密大師是一個工具,通過移動加密的方式實現保護資料夾原檔案。這個軟體是我從老爸電腦上拷貝的。小時候覺得挺神奇的,也找不到檔案在哪裡。現在我們一探究竟,移動加密到底是何方神聖。移動加密是怎麼加密,如何解密的。這軟體好像從網上找不到了,會在文章中提供下載連結。使用時建議使用管理員許可權啟動,否則加密和解密操作會彈出煩人的無法建立dll錯誤。這個dll也不是啥正常dll,而是儲存程式執行路徑的普通文字檔案,只是用dll字尾表示而已,沒啥用處。本篇的重點是分析一下它是如何加密的,如何解密的。

主角和工具

探測

  加密效果如下圖所示(其實我覺得你能猜到我輸入的密碼是什麼):

  既然是加密並且能夠還原,它必須存在,只是咱沒有看到而已,我們使用XYExplorer檢視。它是一個十分強大的工具,任何隱藏檔案都能看到,如下圖所示加密後的情況:

  解密效果如下圖所示:

初步分析

  既然工具使用已經探測完畢了,我們來進入分析環節。先用Detect it easy 1.01探測一下:

  可以檢測到是Delphi寫的,加了一個UPX殼。UPX殼是壓縮殼,只是用來壓縮體積軟體體積用的,並沒有其他任何用途。它將壓縮後的程式碼解壓後會直接跳到主程式程式碼,不會對堆疊造成任何影響。可以用UPX

解壓工具進行解壓,也可以根據堆疊平衡原理手脫。手動脫殼就不介紹了,這個不是本篇的重點,就拿CFF Explorer附加的UPX Utility進行解壓儲存得到。它是一個分析PE結構的一個工具,不過拿來脫UPX殼有點大材小用。
  由於是Delphi寫的,它有自己的特色,通過PE Explorer可以查得它具有一個窗體,名叫TForm1,點選資源檢視可以檢視它的資源,找到關鍵函式。

  然後把它拖到IDA中,等待其分析完畢後,得到如下結果:

  直接在函式列表搜尋Button1Click,找到正確的函式,然後F5一下,看看大體的執行流程,如下圖所示:

  然後大體分析一下,找到疑似為加密虛擬碼片:

System::__linkproc__ LStrCat(&System__AnsiString, &str_Thumbs_dn__4[1]);
if ( !Sysutils::DirectoryExists(System__AnsiString) )
{
  sub_402910(System__AnsiString);
  Sysutils::FileSetAttr(System__AnsiString, 7u);
}
(*(*dword_4B0DBC + 68))(dword_4B0DBC);
Controls::TControl::GetText(*(v60 + 194));
TForm1_jiami3(v60, v49, &v50);
v16 = v50;
System::__linkproc__ LStrCat3(&v48, System__AnsiString, &str_117789687_1[1]);
sub_4AB4BC(v48, v16, v51);
sub_4AB9A8(v55, System__AnsiString);
(*(*dword_4B0DBC + 28))(dword_4B0DBC, &v45);
TForm1_jiami3(v60, v45, &v46);
v16 = v46;
System::__linkproc__ LStrCat3(&v44, System__AnsiString, &str_117789687LIST_m_0[1]);
sub_4AB4BC(v44, v16, v47);
sub_4ABD0C(v55, System__AnsiString);
sub_40B214(v55, &v43);
System::__linkproc__ LStrLAsg(&v55, v43);
v16 = &str___ShellClassInf[1];
v4 = sub_4AB95C(&str_Folder[1], &str_______1[1]);
unknown_libname_78(&v42, v4);
v15 = v42;
v14 = &str____10[1];
unknown_libname_912(*off_4AF5CC, v41);
Sysutils::ExtractFileName(v41[0]);
System::__linkproc__ LStrCatN(
  &v58,
  9,
  v5,
  v15,
  &str____10[1],
  &str_IconIndex_2[1],
  &str____10[1],
  &str_IconFile_[1],
  v41[1],
  &str____10[1],
  &str_ConfirmFileOp_1[1]);
System::__linkproc__ LStrLAsg(&v57, &str___ShellClassInf_0[1]);
System::__linkproc__ LStrCat3(&v39, v55, &str_desktop_ini[1]);
sub_4AB4BC(v39, v58, v40);
System::__linkproc__ LStrCat3(&v37, System__AnsiString, &str_desktop_ini[1]);
sub_4AB4BC(v37, v57, v38);
System::__linkproc__ LStrCat3(&v36, System__AnsiString, &str_desktop_ini[1]);
Sysutils::FileSetAttr(v36, 7u);
System::__linkproc__ LStrCat3(&v35, v55, &str_desktop_ini[1]);
Sysutils::FileSetAttr(v35, 7u);
Sysutils::FileSetAttr(v55, 1u);
Classes::TStrings::Append(dword_4B0DB8, v55);
sub_4AC734(&v34);
System::__linkproc__ LStrCat(&v34, &str_danine_dll[1]);
(*(*dword_4B0DB8 + 116))(dword_4B0DB8, v34);
Forms::TCustomForm::Close(v60);

  通過程式設計經驗,System::__linkproc__ LStrCat函式等函式名相似的函式就是來連線字串的。我們也看到熟悉的中國式命名函式方式的函式TForm1_jiami3,直接把一個疑似加密的函式給暴露了,真是“加密”的拼音啊。

  然後我們在看一看它使用的關鍵字串:

  我之前一直在強調虛擬碼的不準確性。為了保證虛擬碼的進一步準確性,我們點選TForm1_jiami3加密函式檢視一下虛擬碼,檢視所謂的加密過程,返回再F5一下。既然點開了,那就分析一下:

int __usercall TForm1_jiami3@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<ebx>, int a4@<edi>, int a5@<esi>)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v16 = 0;
  v15 = 0;
  v14 = 0;
  v13 = a3;
  v12 = a5;
  v11 = a4;
  v17 = a2;
  v18 = a1;
  System::__linkproc__ LStrAddRef(a1);
  v10 = &savedregs;
  v9[1] = &loc_4ADBFD;
  v9[0] = NtCurrentTeb()->NtTib.ExceptionList;
  __writefsdword(0, v9);
  v5 = 1;
  v6 = unknown_libname_82(v18);
  if ( v6 > 0 )
  {
    v7 = 1;
    do
    {
      v5 ^= 1u;
      if ( v5 )
      {
        Sysutils::IntToHex(*(v18 + v7 - 1) ^ 4, 2);
        System::__linkproc__ LStrCat(&v16, v15);
      }
      else
      {
        Sysutils::IntToHex(*(v18 + v7 - 1) ^ 5, 2);
        System::__linkproc__ LStrCat(&v16, v14);
      }
      ++v7;
      --v6;
    }
    while ( v6 );
  }
  System::__linkproc__ LStrCat3(v17, &str___35[1], v16);
  __writefsdword(0, v9[0]);
  v10 = &loc_4ADC04;
  System::__linkproc__ LStrArrayClr(&v14, 3);
  return System::__linkproc__ LStrClr(&v18);
}

  輸入的必然是字串,如果加密字串,必然會讀取每個字元。通過這個程式設計經驗,可以暫定v18即引數a1是我們傳遞的待加密字串。

  從目前看,程式加密時,會通過Controls::TControl::GetText這個函式獲取你輸入的明文密碼,存放到*(v60 + 194)這個地址中,v60必定是這個窗體類的一個部分或者直接是這個窗體類。獲取後傳遞到TForm1_jiami3加密函式進行加密通過v50這個引數傳遞出去,v17即引數a2就是獲得加密後的字串。加密過程就是逐個字元取出,然後交替用54進行異或,然後轉換為兩個字元的字串,依次連線,再最終結果連線到str___35字串後面,我們來看看這個字串到底是什麼。

  可以看出,這個字串不能夠正常顯示,它如果表示就是/x02。這個加密過程我們就清晰了。
  然後返回看看,發現原來的虛擬碼變了。然後再把沒函式名的點選一下然後返回,最終是這個樣子:

System::__linkproc__ LStrCat(&System__AnsiString, &str_Thumbs_dn__4[1]);
if ( !Sysutils::DirectoryExists(System__AnsiString) )
{
  sub_402910(System__AnsiString);
  Sysutils::FileSetAttr(System__AnsiString, 7u);
}
(*(*dword_4B0DBC + 68))(dword_4B0DBC);
Controls::TControl::GetText(*(v59 + 194));
TForm1_jiami3(v49, &v50, a2, a3, a4);
v19 = v50;
System::__linkproc__ LStrCat3(&v48, System__AnsiString, &str_117789687_1[1]);
sub_4AB4BC(v48, v19);
sub_4AB9A8(v54, System__AnsiString, a2);
(*(*dword_4B0DBC + 28))(dword_4B0DBC, &v46);
TForm1_jiami3(v46, &v47, a2, a3, a4);
v19 = v47;
System::__linkproc__ LStrCat3(&v45, System__AnsiString, &str_117789687LIST_m_0[1]);
sub_4AB4BC(v45, v19);
sub_4ABD0C(v54, System__AnsiString, a2);
sub_40B214(v54, &v44);
System::__linkproc__ LStrLAsg(&v54, v44);
v19 = &str___ShellClassInf[1];
v7 = sub_4AB95C(&str_Folder[1], &str_______1[1]);
unknown_libname_78(&v43, v7);
v18 = v43;
v17 = &str____10[1];
unknown_libname_912(*off_4AF5CC, v42);
Sysutils::ExtractFileName(v42[0]);
System::__linkproc__ LStrCatN(
  &v57,
  9,
  v8,
  v18,
  &str____10[1],
  &str_IconIndex_2[1],
  &str____10[1],
  &str_IconFile_[1],
  v42[1],
  &str____10[1],
  &str_ConfirmFileOp_1[1]);
System::__linkproc__ LStrLAsg(&v56, &str___ShellClassInf_0[1]);
System::__linkproc__ LStrCat3(&v41, v54, &str_desktop_ini[1]);
sub_4AB4BC(v41, v57);
System::__linkproc__ LStrCat3(&v40, System__AnsiString, &str_desktop_ini[1]);
sub_4AB4BC(v40, v56);
System::__linkproc__ LStrCat3(&v39, System__AnsiString, &str_desktop_ini[1]);
Sysutils::FileSetAttr(v39, 7u);
System::__linkproc__ LStrCat3(&v38, v54, &str_desktop_ini[1]);
Sysutils::FileSetAttr(v38, 7u);
Sysutils::FileSetAttr(v54, 1u);
Classes::TStrings::Append(dword_4B0DB8, v54);
sub_4AC734(&v37);
System::__linkproc__ LStrCat(&v37, &str_danine_dll[1]);
(*(*dword_4B0DB8 + 116))(dword_4B0DB8, v37);
Forms::TCustomForm::Close(v59);

  然後我們繼續接著Controls::TControl::GetText(*(v59 + 194));這條程式碼後面講解。發現函式呼叫過程跟我們的猜測完全一致,註釋如下:

Controls::TControl::GetText(*(v59 + 194));// 獲取明文密碼
TForm1_jiami3(input, &enstr, a2, a3, a4);// 進行加密操作
buffer = enstr;
System::__linkproc__ LStrCat3(&v48, System__AnsiString, &str_117789687_1[1]);
sub_4AB4BC(v48, buffer);

  根據探測,先推測這個是一個寫檔案的函式,因為v48推測是一個檔案路徑,還有傳入存有加密字串的buffer。我們雙擊這個函式檢視如下所示:

int __fastcall sub_4AB4BC(int a1, int a2)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v7 = a2;
  v8 = a1;
  System::__linkproc__ LStrAddRef(a1);
  System::__linkproc__ LStrAddRef(v7);
  v5 = &savedregs;
  v4[1] = &loc_4AB543;
  v4[0] = NtCurrentTeb()->NtTib.ExceptionList;
  __writefsdword(0, v4);
  *off_4AF66C = 2;
  System::__linkproc__ Assign(v6, v8);
  System::__linkproc__ RewritText(v6);
  v2 = sub_404CB0(v6, v7);
  System::__linkproc__ Flush(v2);
  System::__linkproc__ Close(v6);
  __writefsdword(0, v4[0]);
  v5 = &loc_4AB54A;
  return System::__linkproc__ LStrArrayClr(&v7, 2);
}

  這不用多說,編寫過讀寫檔案程式設計的人都知道這個函式的功能了吧?
  然後繼續分析下一個程式碼片

sub_4AB9A8(v54, System__AnsiString, a2);
(*(*dword_4B0DBC + 28))(dword_4B0DBC, &v46);
TForm1_jiami3(v46, &v47, a2, a3, a4);
v19 = v47;
System::__linkproc__ LStrCat3(&v45, System__AnsiString, &str_117789687LIST_m_0[1]);
sub_4AB4BC(v45, v19);

  sub_4AB9A8這個函式不知道是幹啥的,然後(*(*dword_4B0DBC + 28))這個函式連名字都沒有,也不知道。但我們可以根據前面的分析肯定。v46就是待加密的字串,v47就是加密後的字串,然後通過sub_4AB4BC函式寫入檔案中。(*(*dword_4B0DBC + 28))這個函式幹啥只能在動態除錯中分析了,我們先分析sub_4AB9A8這個函式:

int __usercall sub_4AB9A8@<eax>(void *a1@<eax>, int a2@<edx>, int a3@<ebx>)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v14 = 0;
  v15 = 0;
  v16 = 0;
  v18 = 0;
  v17 = 0;
  v19 = 0;
  v23 = 0;
  v24 = a2;
  v25 = a1;
  System::__linkproc__ LStrAddRef(a1);
  System::__linkproc__ LStrAddRef(v24);
  unknown_libname_89(FatTime, &byte_407C18);
  v12 = &savedregs;
  v11 = &loc_4ABC29;
  v10 = NtCurrentTeb()->NtTib.ExceptionList;
  __writefsdword(0, &v10);
  (*(*dword_4B0DBC + 68))(dword_4B0DBC, *dword_4B0DBC);
  v3 = 0;
  v4 = unknown_libname_82(v25);
  v5 = *(v25 + v4 - 1) - 47;
  if ( v5 && v5 != 45 )
    System::__linkproc__ LStrCat(&v25, &str___30[1]);
  v6 = unknown_libname_82(v24);
  v7 = *(v24 + v6 - 1) - 47;
  if ( v7 && v7 != 45 )
    System::__linkproc__ LStrCat(&v24, &str___30[1]);
  System::__linkproc__ LStrCat3(&v19, v25, &str___31[1]);
  if ( !Sysutils::FindFirst(v19, 63, FatTime) )
  {
    do
    {
      System::__linkproc__ LStrCmp(System__AnsiString, &str____0[1]);
      if ( !v8 )
      {
        System::__linkproc__ LStrCmp(System__AnsiString, &str___6[1]);
        if ( !v8 )
        {
          unknown_libname_912(*off_4AF5CC, &v17);
          Sysutils::ExtractFileName(v17);
          System::__linkproc__ LStrCmp(System__AnsiString, v18);
          if ( !v8 )
          {
            System::__linkproc__ LStrCmp(System__AnsiString, &str___exesoft_0[1]);
            if ( !v8 )
            {
              sub_40B268(&str_Thumbs_dn__1[1]);
              System::__linkproc__ LStrCmp(System__AnsiString, v16);
              if ( !v8 )
              {
                System::__linkproc__ LStrCmp(System__AnsiString, &str__________exe_0[1]);
                if ( !v8 )
                {
                  System::__linkproc__ LStrCmp(System__AnsiString, &str_System_Volume_I[1]);
                  if ( !v8 )
                  {
                    ++v3;
                    Classes::TStrings::Append(dword_4B0DBC, System__AnsiString);
                    if ( (v21 & 0x10) == 16 )
                    {
                      Sysutils::IntToStr(v3);
                      System::__linkproc__ LStrCat3(&v23, v15, &str___2227a280_3aea[1]);
                    }
                    else
                    {
                      Sysutils::IntToStr(v3);
                      System::__linkproc__ LStrCat3(&v23, v14, &str__mem[1]);
                    }
                    Classes::TStrings::Append(dword_4B0DBC, v23);
                  }
                }
              }
            }
          }
        }
      }
    }
    while ( !Sysutils::FindNext(FatTime) );
    Sysutils::FindClose(FatTime);
  }
  __writefsdword(0, v11);
  v13 = &loc_4ABC30;
  System::__linkproc__ LStrArrayClr(&v14, 6);
  System::__linkproc__ FinalizeRecord(FatTime, &byte_407C18);
  System::__linkproc__ LStrArrayClr(&v23, 3);
  return a3;
}

  雖然有很多大量我不知道的東西,但可以明確知道它是在遍歷檔案,如果是我想要的檔案就貼在dword_4B0DBC這個字串後面。我們可以確定這個是儲存遍歷後的字串資訊,把它定義為files,然後返回,發現虛擬碼發生了一些變化。

sub_4AB9A8(v54, System__AnsiString, a2);
(*(*files + 28))(files, &v46);
TForm1_jiami3(v46, &v47, a2, a3, a4);
buffer = v47;
System::__linkproc__ LStrCat3(&v45, System__AnsiString, &str_117789687LIST_m_0[1]);
sub_4AB4BC(v45, buffer);

  我們發現沒有函式名的變成了有些意義的東西,剩下的轉交給我們的X32Dbg,在合適的地方下斷點,定位到我們有疑點的地方:

  這個函式是用來寫檔案的,是我們之前推測判定的,通過XYExplorer成功驗證:

  分析到那個名字不知道的函式,根據IDA和結果跟蹤發現是Classes::TStrings::GetTextStr這個函式:

  執行完這個函式,發現返回值是一個相當長的字串,為了清晰,我們再跟一步:

  然後我們再從記憶體視窗觀察引數,如下圖所示,清晰明瞭。

  最終經過TForm1_jiami3函式加密,然後寫到檔案裡面。可以看出這個是儲存加密檔案資訊的,儲存著檔名。
  後面的就不再領大家繼續分析了。我就大體說一下,後面是開始寫desktop.ini。這個檔案是用來個性化資料夾,再賦予合適的屬性,以實現隱藏。然後把待加密的檔案挪到Thumbs.dn這個資料夾。建立Dll,直接寫入當前檔案目錄路徑,最終加密結束。

反制還原

  由於加密機制十分簡單,我們完全可以進行解密反制。我們不光可以獲取它的密碼,甚至把檔案都給還原回去。我們通過C++進行,有關字串的解密措施可以寫出如下函式:

void CulockCrackerDlg::Decode(BYTE* encryptedData, INT bufferlen, CHAR* out)
{
    BOOL b = FALSE;
    BYTE item;

    int i = 0;
    int h, l;
    for (; i < bufferlen - 1; i++)
    {
        h = encryptedData[2 * i];
        if (h >= '0' && h <= '9')
        {
            h -= '0';
        }
        else
        {
            h = h - 'A' + 10;
        }

        l = encryptedData[2 * i + 1];
        if (l >= '0' && l <= '9')
        {
            l -= '0';
        }
        else
        {
            l = l - 'A' + 10;
        }


        item = h * 16 + l;
        if (b)
        {
            item ^= 4;
        }
        else
        {
            item ^= 5;
        }
        b = !b;
        out[i] = item;
    }

    out[i] = 0;
}

  為什麼程式碼看起來有點怪怪的呢?因為我建立了一個俗稱沒飯吃(MFC)的專案。我寫的專案已經完成了解密密碼和還原加密的功能。這裡我只貼核心程式碼,剩下的自己還是寫一寫吧。
  接下來我們解密密碼:

void CulockCrackerDlg::OnBnClickedBtnGetPwd()
{
    UpdateData();    //更新folderName,這個儲存的是文字框內的值
                     //folderName儲存是被加密的資料夾
    WCHAR pathbuffer[MAX_PATH + 1];
    INT len = folderName.GetLength();
    folderName.CopyChars(pathbuffer, MAX_PATH + 1, folderName, len);

    StrCpy(&pathbuffer[len], L"\\Thumbs.dn");

    if (!DirectoryExists(pathbuffer))    //這個函式是我自定義寫的,別以為庫函式有
    {
        MessageBox(L"不是 ulock 移動加密的資料夾!!!", appName, MB_ICONERROR);
        return;
    }

    StrCpy(&pathbuffer[len], L"\\Thumbs.dn\\117789687");

    if (!FileExists(pathbuffer))    //這個函式是我自定義寫的,別以為庫函式有
    {
        MessageBox(L"密碼檔案未找到!!!", appName, MB_ICONERROR);
        return;
    }

    CFile hfile;
    if (!hfile.Open(pathbuffer, CFile::modeRead | CFile::typeBinary))
    {
        MessageBox(L"開啟密碼檔案失敗!!!", appName, MB_ICONERROR);
        return;
    }

    hfile.Seek(1, CFile::begin);    //忽略第一個位元組,這個位元組沒用處

    UINT flen = (UINT)hfile.GetLength() - 1;
    BYTE* buffer = new BYTE[flen];
    hfile.Read(buffer, flen);
    hfile.Close();

    INT declen = flen / 2 + 1;
    CHAR* decodestring = new CHAR[declen];
    Decode(buffer, declen, decodestring);    //呼叫解密函式

    txtInfo.AppendFormat(L"> 資料夾密碼:\t%s\r\n", CString(decodestring));
    UpdateData(0);

    delete[] decodestring;
    delete[] buffer;
}

  還原加密程式碼:

void CulockCrackerDlg::OnBnClickedBtnGetFiles()
{
    UpdateData();

    txtInfo.Append(L">> 正在檢測是否為 ulock 加密……\r\n");
    UpdateData(0);

    CString encryptfolder(folderName);
    encryptfolder.Append(L"\\Thumbs.dn");

    if (!DirectoryExists(encryptfolder))    //這個函式是我自定義寫的,別以為庫函式有
    {
        MessageBox(L"不是 ulock 移動加密的資料夾!!!", appName, MB_ICONERROR);
        ShowErr();    //展示錯誤資訊,自定義函式
        return;
    }

    txtInfo.Append(L">> 正在獲取加密檔案結構資訊……\r\n");
    UpdateData(0);

    SetCurrentDirectory(encryptfolder);

    WCHAR prefix[] = L"117789687LIST.mem";

    if (!FileExists(prefix))    //這個函式是我自定義寫的,別以為庫函式有
    {
        MessageBox(L"資料夾資訊檔案未找到!!!", appName, MB_ICONERROR);
        ShowErr();    //展示錯誤資訊,自定義函式
        return;
    }

    CFile hfile;
    if (!hfile.Open(prefix, CFile::modeRead | CFile::typeBinary))
    {
        MessageBox(L"加密檔案結構資訊檔案未找到!!!", appName, MB_ICONERROR);
        ShowErr();    //展示錯誤資訊,自定義函式
        return;
    }

    hfile.Seek(1, CFile::begin);    //跳過第一個無用位元組

    UINT flen = (UINT)hfile.GetLength() - 1;
    BYTE* buffer = new BYTE[flen];
    hfile.Read(buffer, flen);
    hfile.Close();

    INT declen = flen / 2 + 1;
    CHAR* decodestring = new CHAR[declen];
    Decode(buffer, declen, decodestring);    //呼叫解密函式

    //分割字串,獲取檔案map
    stringstream ss;
    ss << decodestring;
    CList<CString> files;
    string str;
    while (!ss.eof())
    {
        getline(ss, str, '\n');
        if (!str.length()) break;
        str.pop_back();    //刪除最後一個字元 '\r'
        files.AddTail(CString(str.c_str()));
    }

    int total = files.GetCount()/2;
    txtInfo.AppendFormat(L">> 獲取成功,共有 %d 組檔案\r\n", total);
    txtInfo.Append(L">> 開始解密……\r\n");
    UpdateData(0);

    auto fp = files.GetHeadPosition();

    for (int i = 0; i < total; i++)
    {
        auto dest = files.GetNext(fp);    //解密後的檔名
        auto src = files.GetNext(fp);    //加密的檔名

        dest.Insert(0, L"..\\");
        SetFileAttributes(src, FILE_ATTRIBUTE_NORMAL);
        MoveFile(src, dest);
    }

    txtInfo.Append(L">> 檔案解密完畢,正在清理無效檔案……\r\n");
    UpdateData(0);

    //還原檔案屬性,防止無法刪除
    if (!SetFileAttributes(prefix, FILE_ATTRIBUTE_NORMAL)|| !DeleteFile(prefix))
    {
        txtInfo.Append(L">> 刪除無效的加密檔案結構資訊失敗,可能檔案不存在或者被佔用。\r\n");
        UpdateData(0);
    }

    prefix[9] = 0;

    //還原檔案屬性,防止無法刪除
    if (!SetFileAttributes(prefix, FILE_ATTRIBUTE_NORMAL) || !DeleteFile(prefix))
    {
        txtInfo.Append(L">> 刪除無效的金鑰檔案失敗,可能檔案不存在或者被佔用。\r\n");
        UpdateData(0);
    }


    WCHAR* p = L"desktop.ini";
    //還原檔案屬性,防止無法刪除
    if (!SetFileAttributes(p, FILE_ATTRIBUTE_NORMAL) || !DeleteFile(p))
    {
        txtInfo.Append(L">> 刪除無效的加密設定失敗,可能檔案不存在或者被佔用。\r\n");
        UpdateData(0);
    }

    p = L"..\\desktop.ini";
    //還原檔案屬性,防止無法刪除
    if (!SetFileAttributes(p, FILE_ATTRIBUTE_NORMAL) || !DeleteFile(p))
    {
        txtInfo.Append(L">> 刪除無效的加密設定失敗,可能檔案不存在或者被佔用。\r\n");
        UpdateData(0);
    }

    //更改當前目錄,以防 Thumbs.dn 資料夾無法刪除
    SetCurrentDirectory(L"..\\");
    p = L"Thumbs.dn";
    //還原檔案屬性,防止無法刪除
    if (!SetFileAttributes(p, FILE_ATTRIBUTE_NORMAL) || !RemoveDirectory(p))
    {
        txtInfo.Append(L">> 刪除無效的加密檔案存放區 Thumbs.dn 失敗,可能資料夾被佔用。\r\n");
        UpdateData(0);
    }

    txtInfo.Append(L">>解密完畢……\r\n");
    UpdateData(0);

    delete[] decodestring;
    delete[] buffer;

    MessageBox(L"解密成功!!!", appName, MB_ICONINFORMATION);
    return;
}

效果展示

  最後工具寫好了,我們來看看效果:

小結

  1. 移動加密不保險,可以比較容易地被還原出來。
  2. 雖然移動加密不保險,但速度快是肯定的。如果通過加密演算法保護必將降低解密和加密效率。

本文來自部落格園,作者:寂靜的羽夏,一個熱愛計算機技術的菜鳥,轉載請註明原文連結:https://www.cnblogs.com/wingsummer/p/15417415.html