AspectC++ Add-In for Microsoft® Visual C++®
http://www.pure-systems.com/fileadmin/downloads/acaddin/Aspectc-AddIn-Setup-010101.exe
我用的是VS2003環(huán)境
調試目標:C:\Program Files\pure-systems\AspectC++ Add-In\bin\CPPAddin.dll
工具:用OD調試,IDA+Hex-rays分析
重點集中在以下幾個地址
0x10008e60 彈許可文件詢問的對話框
0x10017a20 解析xml格式的許可文件
0x10017730 貌似許可檢查的地方
這個是
0x10008e60的由Hex-ray分析出來的偽代碼,
代碼:
char __usercall sub_1000E860<al>(int a1<ebx>)
{
int ST14_4_0; // ST14_4@0
int v2; // ST10_4@1
const CHAR *v3; // eax@3
const CHAR *v4; // eax@10
int v6; // eax@2
char v7; // bl@2
char v8; // al@9
int v9; // [sp+Ch] [bp-9Ch]@1
signed int v10; // [sp+A4h] [bp-4h]@1
char v11; // [sp+10h] [bp-98h]@1
char v12; // [sp+48h] [bp-60h]@2
char v13; // [sp+2Ch] [bp-7Ch]@2
LPCSTR lpText; // [sp+14h] [bp-94h]@3
unsigned int v15; // [sp+28h] [bp-80h]@3
char v16; // [sp+64h] [bp-44h]@15
BYTE3(v9) = 0;
sub_10016AA0();
v10 = 0;
std__basic_string_char_std__char_traits_char__std__allocator_char____basic_string_char_std__char_traits_char__std__allocator_char__(&v11);
LOBYTE(v10) = 1;
v2 = a1;
while ( 1 )
{
sub_100169B0(16, (int)&v12);
LOBYTE(v10) = 2;
v6 = std__operator_(&v13, v6, "\\etc\\licence");
LOBYTE(v10) = 3;
v7 = sub_10017A20((int)&unk_10024460, v6, (int)&v11) == 0;
LOBYTE(v10) = 2;
std__basic_string_char_std__char_traits_char__std__allocator_char_____basic_string_char_std__char_traits_char__std__allocator_char__(&v13);
LOBYTE(v10) = 1;
std__basic_string_char_std__char_traits_char__std__allocator_char_____basic_string_char_std__char_traits_char__std__allocator_char__(&v12);
if ( !v7 )
break;
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(
&v11,
"\nThe add-in will not work without a valid licence.\n\nInstall the licence file now?",
v2);
v3 = lpText;
if ( v15 < 0x10 )
v3 = (const CHAR *)&lpText;
if ( MessageBoxA(0, v3, "AspectC++ Add-In for Visual Studio .NET", 0x24u) != 6 )
break;
if ( !sub_1000E690() )
{
MessageBoxA(0, "Installation of licence file failed.", "AspectC++ Add-In", 0x40u);
break;
}
}
if ( byte_10024465 )
{
sub_10017730((int)&unk_10024460, 16, (int)&v11);
if ( v8 && (unsigned __int8)sub_10017520(&v11) != 1 )
{
BYTE3(v9) = 1;
}
else
{
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(
&v11,
"\nThe add-in will not work.",
ST14_4_0);
v4 = lpText;
if ( v15 < 0x10 )
v4 = (const CHAR *)&lpText;
MessageBoxA(0, v4, "AspectC++ Add-In", 0x40u);
}
}
LOBYTE(v10) = 0;
std__basic_string_char_std__char_traits_char__std__allocator_char_____basic_string_char_std__char_traits_char__std__allocator_char__(&v11);
v10 = -1;
sub_10016910((int)&v16);
return BYTE3(v9);
}
基本上可以得出默認是分析
C:\Program Files\pure-systems\AspectC++ Add-In\etc\licence 許可文件
分析過程應該在0x10017a20里
代碼:
char __thiscall sub_10017A20(int this, int a2, int a3)
{
int v3; // ebp@1
int v4; // esi@1
int v5; // eax@2
int v6; // eax@4
int v7; // edi@5
char result; // al@8
int v9; // ecx@1
int v10; // eax@5
int v11; // eax@6
int v12; // ST04_4@6
char v13; // bl@6
char v14; // [sp+Ch] [bp-28h]@6
signed int v15; // [sp+30h] [bp-4h]@6
v3 = a3;
v4 = this;
v9 = this + 96;
*(_DWORD *)v9 = 0;
*(_DWORD *)(v9 + 4) = 0;
*(_DWORD *)(v9 + 8) = 0;
*(_DWORD *)(v9 + 12) = 0;
*(_BYTE *)(v4 + 5) = 0;
std__basic_string_char_std__char_traits_char__std__allocator_char____operator_(v3, "Loading licence file failed.");
if ( *(_DWORD *)(a2 + 24) < 0x10u )
v5 = a2 + 4;
else
v5 = *(_DWORD *)(a2 + 4);
v6 = xmlParseFile(v5);
*(_DWORD *)v4 = v6;
if ( v6
&& (v10 = xmlDocGetRootElement(v6), v7 = v10, v10)
&& (v11 = std__basic_string_char_std__char_traits_char__std__allocator_char____basic_string_char_std__char_traits_char__std__allocator_char__(
&v14,
"licence"), v12 = *(_DWORD *)(v7 + 8), v15 = 0, v13 = std__operator__(v11, v12), v15 = -1, std__basic_string_char_std__char_traits_char__std__allocator_char_____basic_string_char_std__char_traits_char__std__allocator_char__(&v14), v13)
&& sub_10017930(v7) )
{
*(_BYTE *)(v4 + 5) = 1;
sub_10017730(v4, v3, v3);
result = 1;
}
else
{
result = 0;
}
return result;
}
這是0x10017730的過程
代碼:
void __userpurge sub_10017730(int this<ecx>, int ebp0<ebp>, int a2)
{
int ST18_4_0; // ST18_4@0
int ST1C_4_0; // ST1C_4@0
int v5; // esi@1
signed int v6; // eax@4
int v7; // ST18_4@6
int v8; // eax@20
int v9; // eax@4
int v10; // ST1C_4@12
int v11; // ST1C_4@18
int r; // [sp+60h] [bp+0h]@1
int v13; // [sp+50h] [bp-10h]@1
signed int v14; // [sp+5Ch] [bp-4h]@3
char v15; // [sp+34h] [bp-2Ch]@4
char v16; // [sp+18h] [bp-48h]@4
int v17; // [sp+1Ch] [bp-44h]@12
unsigned int v18; // [sp+30h] [bp-30h]@20
int v19; // [sp+2Ch] [bp-34h]@22
v5 = this;
v13 = r ^ dword_100242D0;
std__basic_string_char_std__char_traits_char__std__allocator_char____operator_(a2, "Invalid licence file found.");
if ( *(_BYTE *)(v5 + 5) && !*(_BYTE *)(v5 + 4) )
{
sub_10017B20((int)&a2, ebp0);
v14 = 0;
if ( !sub_1001A050((int)&a2) )
{
LABEL_23:
v14 = -1;
sub_1001A060(&a2);
goto LABEL_24;
}
v9 = std__operator_(&v15, v5 + 12, v5 + 40);
LOBYTE(v14) = 1;
std__operator_(&v16, v9, v5 + 68);
LOBYTE(v14) = 3;
std__basic_string_char_std__char_traits_char__std__allocator_char_____basic_string_char_std__char_traits_char__std__allocator_char__(&v15);
v6 = *(_DWORD *)(v5 + 8);
if ( v6 || !*(_DWORD *)(v5 + 96) )
{
if ( v6 == 1 && *(_DWORD *)(v5 + 96) && *(_DWORD *)(v5 + 100) && *(_DWORD *)(v5 + 104) && *(_DWORD *)(v5 + 108) )
{
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v16, "evaluation", ST18_4_0);
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(
&v17,
*(_DWORD *)(v5 + 96),
ST1C_4_0);
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(
&v17,
*(_DWORD *)(v5 + 100),
v10);
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(
&v17,
*(_DWORD *)(v5 + 104),
ST1C_4_0);
v7 = *(_DWORD *)(v5 + 108);
}
else
{
if ( v6 != 2
|| !*(_DWORD *)(v5 + 96)
|| !*(_DWORD *)(v5 + 100)
|| !*(_DWORD *)(v5 + 104)
|| !*(_DWORD *)(v5 + 108) )
goto LABEL_20;
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v16, "user", ST18_4_0);
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(
&v17,
*(_DWORD *)(v5 + 96),
ST1C_4_0);
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(
&v17,
*(_DWORD *)(v5 + 100),
v11);
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(
&v17,
*(_DWORD *)(v5 + 104),
ST1C_4_0);
v7 = *(_DWORD *)(v5 + 108);
}
}
else
{
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v16, "beta", ST18_4_0);
v7 = *(_DWORD *)(v5 + 96);
}
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v17, v7, ST1C_4_0);
LABEL_20:
v8 = v17;
if ( v18 < 0x10 )
v8 = (int)&v17;
*(_BYTE *)(v5 + 4) = sub_10019E30(v5 + 112, v8, v19, (int)&a2);
LOBYTE(v14) = 0;
std__basic_string_char_std__char_traits_char__std__allocator_char_____basic_string_char_std__char_traits_char__std__allocator_char__(&v16);
goto LABEL_23;
}
LABEL_24:
sub_1001A7B0( r ^ v13, ebp0);
}
昨天我自己調試的時候也犯了一個錯誤,就是調試CppAddin.dll很痛苦,浪費不少時間和分散很多的精力,中間老是受到Va_X.dll的干擾,而且msdev.exe在CppAddin沒加載時沒法直接下斷點,必須得在OD中設置一個新模塊加載的斷點(選項->調試選項->事件->中斷于新模塊),這樣下來,每次調試失敗后重啟的過程很是漫長,浪費了不少時間,發(fā)帖子的求助的時候,我為了大大們給我能方便的解決問題,盡量把非技術問題都試驗了一下,以免大大們被這些問題困住了,一怒之下不給我管我了。但是這樣一來,也為我自己解決和發(fā)現(xiàn)問題加快了速度。
總結一下:
1.解決問題要東方不亮,西方亮,不要將自己精力消耗在遠離問題本身的地方
2.堅持就是勝利,哪怕是菜鳥,不懂多少匯編(看代碼還得靠偉大、光榮、正確的F5),也能取得成績
下面寫寫分析過程:
其實昨天已經(jīng)找到了關鍵的過程,那就是0x10017a20,這里面就是分析xml格式的許可文件
這里面有兩個調用,sub_10017930()和 sub_10017730()
大概可以看得出來,sub_10017930參與了xml格式的許可數(shù)據(jù)的解析過程,它調用成功之后,才調用10017730對數(shù)據(jù)進行驗證,要分析許可數(shù)據(jù)格式,必須研究10017930
代碼:
char __stdcall sub_10017930(int a1)
{
int v1; // ebp@1
int v2; // esi@1
int v3; // esi@3
char result; // al@7
int v5; // eax@1
int v6; // eax@2
char v7; // bl@2
char v8; // [sp+Ch] [bp-28h]@2
signed int v9; // [sp+30h] [bp-4h]@2
v1 = a1;
v5 = xmlGetProp(a1, "version");
v2 = v5;
if ( v5
&& (v6 = std__basic_string_char_std__char_traits_char__std__allocator_char____basic_string_char_std__char_traits_char__std__allocator_char__(
&v8,
L"1"), v9 = 0, v7 = std__operator__(v6, v2), v9 = -1, std__basic_string_char_std__char_traits_char__std__allocator_char_____basic_string_char_std__char_traits_char__std__allocator_char__(&v8), v7) )
{
v3 = *(_DWORD *)(v1 + 12);
result = (unsigned __int8)sub_10016D60(*(_DWORD *)(v1 + 12))
&& (unsigned __int8)sub_10016E70(v3)
&& (unsigned __int8)sub_10017570(v3)
&& (unsigned __int8)sub_100172C0(v3);
}
else
{
result = 0;
}
return result;
}
在這里面取了xml的一個屬性值version,并且還有四個都不能失敗的過程:
10016d60 取product 元素
10016e70 取creation 元素
10017570 取type元素
100172c0 取signature元素
為了熟悉libxml,我特意編寫了一段典型libxml用法,并分析了其反向工程后的代碼,
代碼:
xmlDocPtr doc = NULL;
xmlNodePtr cur = NULL;
string filename("test.xml");
doc = xmlParseFile(filename.c_str());
cur = xmlDocGetRootElement(doc);
if (xmlStrcmp(cur->name, BAD_CAST "licence"))
{
fprintf(stderr,"document of the wrong type, root node != mail");
xmlFreeDoc(doc);
/*return -1; */
}
cur = cur->xmlChildrenNode;
xmlNodePtr propNodePtr = cur;
while(cur != NULL)
{
//¨¨?3??¨²¦Ì??D¦Ì??¨²¨¨Y
if ((!xmlStrcmp(cur->name, (const xmlChar *)"product")))
{
string name;
string version;
xmlChar* szAttr = xmlGetProp(cur,BAD_CAST "name");
name=(char*)szAttr;
szAttr=xmlGetProp(cur,BAD_CAST "version");
version=(const char *)szAttr;
cout<<"Name:"<<name<<" Version:"<<version<<endl;
xmlFree(szAttr);
}
cur=cur->next;
}
xmlFreeDoc(doc);
/*return 0;*/
得出的結論是,凡是屬性值的獲取,都會調用xmlGetProp,而子元素的獲取則是通過直接訪問內存結構或者類似c++的函數(shù)訪問,不會看到函數(shù)名稱的引用,根據(jù)這一結論和具體的調試,大致推出來licence文件的結構如下:
代碼:
<?xml version="1.0" encoding="UTF-8"?>
<licence version="1">
<product name="aspect" version="1.0"/>
<product name="pointcut" version="1.0" />
<product name="advice" version="1.0" />
<product name="slice" version="1.0" />
<creation date="2009-8-13"/>
<type name="user">
<data code="xxxx" name="jans2002" email="jans2002@gmail.com" regnr="ccccc"/>
</type>
<signature sign="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" />
</licence>
有了這個licence文件,把它放到
C:\Program Files\pure-systems\AspectC++ Add-In\etc\目錄下
一切問題就變得簡單了,順利執(zhí)行完了0x10017930,一路殺到0x10017730
代碼:
int __thiscall sub_10017730(int this, int a2)
{
int v2; // esi@1
signed int v3; // eax@4
int v4; // ST14_4@6
int v5; // eax@20
int v7; // eax@4
int r; // [sp+4Ch] [bp+0h]@1
int v9; // [sp+3Ch] [bp-10h]@1
signed int v10; // [sp+48h] [bp-4h]@3
char v11; // [sp+20h] [bp-2Ch]@4
char v12; // [sp+4h] [bp-48h]@4
int v13; // [sp+8h] [bp-44h]@20
unsigned int v14; // [sp+1Ch] [bp-30h]@20
int v15; // [sp+18h] [bp-34h]@22
v2 = this;
v9 = r ^ dword_100242D0;
std__basic_string_char_std__char_traits_char__std__allocator_char____operator_(a2, "Invalid licence file found.");
if ( *(_BYTE *)(v2 + 5) && !*(_BYTE *)(v2 + 4) )
{
sub_10017B20();
v10 = 0;
if ( !(unsigned __int8)sub_1001A050() )
{
LABEL_23:
v10 = -1;
sub_1001A060();
return sub_1001A7B0();
}
v7 = std__operator_(&v11, v2 + 12, v2 + 40);
LOBYTE(v10) = 1;
std__operator_(&v12, v7, v2 + 68);
LOBYTE(v10) = 3;
std__basic_string_char_std__char_traits_char__std__allocator_char_____basic_string_char_std__char_traits_char__std__allocator_char__(&v11);
v3 = *(_DWORD *)(v2 + 8);
if ( v3 || !*(_DWORD *)(v2 + 96) )
{
if ( v3 == 1 && *(_DWORD *)(v2 + 96) && *(_DWORD *)(v2 + 100) && *(_DWORD *)(v2 + 104) && *(_DWORD *)(v2 + 108) )
{
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, "evaluation");
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, *(_DWORD *)(v2 + 96));
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, *(_DWORD *)(v2 + 100));
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, *(_DWORD *)(v2 + 104));
v4 = *(_DWORD *)(v2 + 108);
}
else
{
if ( v3 != 2
|| !*(_DWORD *)(v2 + 96)
|| !*(_DWORD *)(v2 + 100)
|| !*(_DWORD *)(v2 + 104)
|| !*(_DWORD *)(v2 + 108) )
goto LABEL_20;
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, "user");
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, *(_DWORD *)(v2 + 96));
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, *(_DWORD *)(v2 + 100));
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, *(_DWORD *)(v2 + 104));
v4 = *(_DWORD *)(v2 + 108);
}
}
else
{
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, "beta");
v4 = *(_DWORD *)(v2 + 96);
}
std__basic_string_char_std__char_traits_char__std__allocator_char____operator__(&v12, v4);
LABEL_20:
v5 = v13;
if ( v14 < 0x10 )
v5 = (int)&v13;
*(_BYTE *)(v2 + 4) = sub_10019E30(v2 + 112, v5, v15, (int)&a2);
LOBYTE(v10) = 0;
std__basic_string_char_std__char_traits_char__std__allocator_char_____basic_string_char_std__char_traits_char__std__allocator_char__(&v12);
goto LABEL_23;
}
return sub_1001A7B0();
}
由于有了正確格式的licence,前面執(zhí)行的都很順利,一直到了sub_10019E30,跟進去一看,一切了然了:
代碼:
bool __thiscall sub_10019E30(int this, int a2, int a3, int a4)
{
int v5; // esi@1
int v6; // eax@1
int v7; // eax@1
char v8; // [sp+4h] [bp-10h]@1
v5 = this;
v6 = EVP_sha1();
EVP_DigestInit(&v8, v6);
EVP_DigestUpdate(&v8, a2, a3);
v7 = sub_1001A030();
return EVP_VerifyFinal(&v8, v5, *(_DWORD *)(v5 + 4096), v7) == 1;
}
前面一定都是加密驗證的,但是函數(shù)最后來了一句:
代碼:
EVP_VerifyFinal(&v8, v5, *(_DWORD *)(v5 + 4096), v7) == 1;
嘿嘿,看名字估計就是這個了,看看這個函數(shù)的返回值,1表示成功,其他表示失敗,那就是只要讓此函數(shù)永遠返回1,就大功告成了,該到匯編代碼了:
代碼:
004066F0 /$ 83EC 10 sub esp, 10 ; 檢查數(shù)字簽名部分
004066F3 |. 56 push esi
004066F4 |. 8BF1 mov esi, ecx
004066F6 |. E8 81270000 call <jmp.&LIBEAY32.#333>
004066FB |. 50 push eax
004066FC |. 8D4424 08 lea eax, dword ptr [esp+8]
00406700 |. 50 push eax
00406701 |. E8 70270000 call <jmp.&LIBEAY32.#268>
00406706 |. 8B4C24 24 mov ecx, dword ptr [esp+24]
0040670A |. 8B5424 20 mov edx, dword ptr [esp+20]
0040670E |. 51 push ecx
0040670F |. 52 push edx
00406710 |. 8D4424 14 lea eax, dword ptr [esp+14]
00406714 |. 50 push eax
00406715 |. E8 56270000 call <jmp.&LIBEAY32.#269>
0040671A |. 8B4C24 34 mov ecx, dword ptr [esp+34]
0040671E |. 83C4 14 add esp, 14
00406721 |. E8 2A100000 call 00407750
00406726 |. 8B8E 00100000 mov ecx, dword ptr [esi+1000]
0040672C |. 50 push eax
0040672D |. 51 push ecx
0040672E |. 8D5424 0C lea edx, dword ptr [esp+C]
00406732 |. 56 push esi
00406733 |. 52 push edx
00406734 |. E8 49270000 call <jmp.&LIBEAY32.#290>
00406739 |. 83C4 10 add esp, 10
0040673C |. 48 dec eax
0040673D |. F7D8 neg eax
0040673F 1BC0 sbb eax, eax
00406741 90 inc eax
00406742 5E pop esi
00406743 83C4 10 add esp, 10
00406746 \. C2 0C00 retn 0C
一般來講,函數(shù)返回值都會用EAX,不管三七二十一了,先吧EAX做了再說,把上面那個黑體的
inc eax 改成nop(呵呵,nop是大家的最愛,機器碼是90了,這是改過的了)
保存到文件。
大功告成哈!!
身為菜鳥,能取得這樣的結果,真是讓人興奮,謝謝各位閱讀,還請各位高手不吝賜教。
下載安裝程序及破解