前言
文件夾加密大師
是一個工具,通過移動加密的方式實現保護文件夾原文件。這個軟件是我從老爸電腦上拷貝的。小時候覺得挺神奇的,也找不到文件在哪里。現在我們一探究竟,移動加密到底是何方神聖。移動加密是怎么加密,如何解密的。這軟件好像從網上找不到了,會在文章中提供下載鏈接。使用時建議使用管理員權限啟動,否則加密和解密操作會彈出煩人的無法創建dll
錯誤。這個dll
也不是啥正常dll
,而是存儲程序運行路徑的普通文本文件,只是用dll
后綴表示而已,沒啥用處。本篇的重點是分析一下它是如何加密的,如何解密的。
主角和工具
- Detect it easy 1.01
- IDA 7.5
- X32Dbg
- ulock 文件夾加密大師 —— 密碼:bhr9
- XYExplorer
- CFF Explorer
- PE Explorer
探測
加密效果如下圖所示(其實我覺得你能猜到我輸入的密碼是什么):
既然是加密並且能夠還原,它必須存在,只是咱沒有看到而已,我們使用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
就是獲得加密后的字符串。加密過程就是逐個字符取出,然后交替用5
和4
進行異或,然后轉換為兩個字符的字符串,依次連接,再最終結果連接到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;
}
效果展示
最后工具寫好了,我們來看看效果:
小結
- 移動加密不保險,可以比較容易地被還原出來。
- 雖然移動加密不保險,但速度快是肯定的。如果通過加密算法保護必將降低解密和加密效率。