1. 程式人生 > >Afkayas.1/AfKayAs.2分析

Afkayas.1/AfKayAs.2分析

第二個和第三個的分析。

Afkayas.1

第二個也是找名稱序列號。查殼後無殼,是VB寫的。照舊先執行下。

VB的彈窗函式是rtcMsgBox,或者通過搜字串"You GetWrong"來定位呼叫位置。

定位到函式內部,然後就找對比的地方,je跳轉就是錯誤的對話方塊

往上翻,vb的一些函式我不太理解做什麼的,通過單步跟,找到了輸入字串以後的一些操作

輸入字串以後,會檢查字串的長度,然後字串長度*0x17CFB計算出一個數Num,這個數加上輸入字串的第一個位元組。這裡需要注意的是,如果是字母或者是數字的話,轉換成ASSIC都是一個位元組就可以,但是如果輸入的是漢字,一個漢字是2個位元組,所以準確來說它取的是輸入的第一個字元。取出第一個字元後,和Num相加,然後呼叫__vbaStrI4這個函式,將數字轉換成字串。__vbaStrl4所在的dll是Msvbvm50.dll。稍後可能用到。這一步就算出了序列號中數字的那一部分。

然後序列號前面要加一個字串"AKA-",拼接好後,和輸入的序列號做比較,正確就彈對的框。

然後嘗試寫了下注冊機

#include<Windows.h>
#include<stdio.h>
#include<stdlib.h>
//#pragma comment(lib,"Msvbvm50.dll")
HMODULE g_hMod = NULL;


//AKA-XXXXX
//字串的長度*0x17CFB
//第一個位元組的ASSIC+計算出的數
//Msvbvm50.dll
//呼叫__vbaStrI4
//函式型別 (*指標變數名)(形參列表)  函式指標的定義
//typedef int(_stdcall * DLLFUNC)(int ,int)
typedef WCHAR*(_stdcall*vbStrCalc)(DWORD num);


char g_ret[30]{};
// 寬字元轉換為多字元(Unicode --> ASCII)
#define  WCHAR_TO_CHAR(lpW_Char, lpChar) \
	WideCharToMultiByte(CP_ACP, NULL, lpW_Char, -1, lpChar, _countof(lpChar), NULL, FALSE);

// 多字元轉換為寬字元(ASCII --> Unicode)
#define  CHAR_TO_WCHAR(lpChar, lpW_Char) \
	MultiByteToWideChar(CP_ACP, NULL, lpChar, -1, lpW_Char, _countof(lpW_Char));

//str,輸入的字串
//len,字串長度
//flag 用來判斷輸入的是字母數字(true),還是漢字(false)
void calcSerial(char *str,int len,bool flag)
{
	vbStrCalc p_Fun = (vbStrCalc)GetProcAddress(g_hMod, "__vbaStrI4");
	DWORD Tmp = 0;
	Tmp = len * 0x17CFB;
	if(flag==true)
	{
		int NumAndAlph = (int)str[0];
		NumAndAlph += Tmp;
		WCHAR* ss = p_Fun(NumAndAlph);
		WCHAR_TO_CHAR(ss, g_ret);
	}
	else
	{
		//漢字要取兩個位元組
		int chinese = 0;
		int aa = str[0];
		int bb = str[1] & 0xFF;
		chinese |= aa;
		chinese <<= 8;
		chinese |= bb;
		chinese += Tmp;
		WCHAR* ss = p_Fun(chinese);
		WCHAR_TO_CHAR(ss, g_ret);
	}
}

int main()
{
	g_hMod = LoadLibrary(L"Msvbvm50.dll");
	char buf[100]{};
	WCHAR bufTmp[100]{};
	printf("Enter Name: ");
	scanf("%s", buf);
	if ((buf[0] & 0x80) == 0)  //判斷漢字還是字母,看第一個位元組最高位是1還是0,0就是漢字母	{
		calcSerial(buf, strlen(buf),true);
	}
	else
	{
		CHAR_TO_WCHAR(buf, bufTmp);
		calcSerial(buf, wcslen(bufTmp),false);
	}
	printf("Serial is:AKA-%s\n", g_ret);
	system("pause");
	return 0;

}

測試

AfKayAs.2

這個第一個是要去一個neg,彈出來的時候,感覺不是messagebox,停留幾秒後這個彈窗自己消失,然後彈出輸序列號的視窗。首先我想既然不是messagebox,那彈出這個東西,再怎麼它也應該是個視窗,建立一個視窗,貼一張圖,然後把視窗邊框都去掉,顯示出來應該就是這樣子。然後我就給createwindows下斷,可一想也不太對,vb建立視窗用的什麼函式呢?查了下也沒查出個所以然,沒招,單步跟跟看。跟了一頓,全在Msvbvm50.dll中

調到F0260c6的時候,F8了一下直接彈出了序列號的那個框,感覺不太對,單步跟進去,果然再單步下去那個neg又出來了,

在F0260C6裡面,看到了這三個函式,視窗的訊息迴圈用的,

通過這些訊息後,到WM_PAINT,彈窗出現

看視窗的情況,Form1就是上面這個視窗,它上面的那個視窗應該就是那個序列號的視窗

WS_CLIPSIBLINGS用於子視窗,設定子視窗不重繪被覆蓋部分.

WS_CLIPCHILDREN樣式主要是用於父視窗,也就是說當在父視窗繪製的時候,父視窗上還有一個子視窗,那麼設定了這個樣式的話,子視窗區域父視窗就不負責繪製。

樣式什麼的慢慢查。在這個視窗下還有一個視窗有WM_POPUP的屬性的視窗,然後接著執行

又建立了一個子視窗。注意有一個ThunderRT5Timer的東西

執行這個程式的時候,彈出這個neg以後,要等幾秒,它才消失,那麼這裡這個Timmer類就值得注意了,除錯過程中當傳送這個訊息後,視窗消失。可以假設一下,程式執行起來,彈出視窗,定時器設定時間,到時間傳送WM_TIMMER,關閉視窗。開始這個視窗可能就是這麼來的。事實上當視窗退出後,視窗列表這個視窗Form1以及定時器那個東西也一併消失。

SetTimer(m_hWnd,1,1000,NULL)

定時器的函式bp SetTimer試了下,我這裡是想找定時器SetTimmer的那個時間,但是沒有思路,只能找到那個時間到達後,傳送的WM_TIMMER訊息,傳送完這個訊息後,這個neg就會消失,如果找到那個時間,也就是定時器時長,把它改成0,那麼效果就是這個彈窗剛出來,定時器時間很短,基本上一出來就傳送WM_TIMER,然後立刻關閉這個視窗,那麼看起來這個視窗好像沒出現一樣,因為這個視窗是在DLL中的程式碼建立的,沒辦法修改,這裡能力有限,暫時是真找不到,有思路求指教。不勝感激

然後就是輸入名稱序列號,來判斷輸入正確。按一貫思路,輸入字串後點擊,會彈MessageBox,那麼就開始找。首先執行它預設有輸入,什麼也不輸就跑一下,結果發現直接彈出這個窗,點選直接退出。

可以看到不同的輸入,出錯的形式不同,執行時錯誤13 型別不匹配 ,執行時錯誤5 無效的呼叫過程或引數。這兩個都算是錯誤輸入問題導致,所以按正常輸入去找名稱和序列號的關係。

正常輸入以後,斷在rtcMsgBox函式開頭,還是棧中返回地址跟隨,進到了呼叫處。引數正是彈窗裡的顯示

而分支的跳轉在上面

然後就看這個je是什麼比較後的判斷,結果並沒有什麼比較,這裡esi做了一個test,改變了zf的值,完成了判斷。

那到這裡,要想知道esi裡面是什麼的值,只能往上繼續找,上面的程式碼很多,我直接找到了函式的開始處位置,一步一步看。

整個序列號的判斷我全截圖了,VB中一些函式意思不太清楚,有些地方不太懂意思

>先計算輸入name的長度

>ret=長度*0x15B38

>取輸入字串第一個字元的值(十六進位制),值+ret

>呼叫__vbaStrI4轉成字串,儲存str0

>呼叫函式檢測不知道什麼東西

>把上面求得字串str0呼叫__vbaR8Str轉化成浮點數 fNum,入棧st0

>記憶體中取一個浮點數10入棧,然後st0=10/5=2

>檢測狀態暫存器的一個值,意義不懂

>st0=fNum+2 是計算後的值,然後呼叫__vbaStrR8將浮點數轉換成字串儲存,字串記作str1

>記憶體清理

>str1呼叫__vbaR8Str轉浮點數 fNum1 入棧

>fNum1=fNum1*3    fNum1=fNum1-2

>fNum1呼叫__vbaStr8轉化成字串str2

 >記憶體清理

>str2 呼叫__vbaR8Str轉成浮點數fNum2

>fNum2=fNum2-(-15.000)

>fNum2呼叫__vbaStrR8轉字串str3,儲存

>記憶體清理

>取自己輸入的序列號,__vbaR8Str轉浮點數f_input入棧st0,然後彈出到棧[ebp-0xE4]上儲存

 >正確的序列號字串str3 轉浮點數fNum3

>f_input/fNum,計算出結果 f_ret,f_ret和常數1比,FST暫存器的值給eax,檢測ah是否為0,為0就彈錯誤框,

>否則,esi=1,之前檢測esi的值到這裡也就清楚了。

描述過程可能不清楚,但總的來說就是輸入的字串進行一系列浮點數操作得出一個浮點數,輸入的序列號也計算出一個浮點數,然後輸入的除以正確的,算出一個結果,改變了FST暫存器,把FST暫存器的值給eax,如果ah的值為0,則輸入的序列號就錯,非0,輸入的序列號就正確。

第二個的註冊機就不寫了,那個浮點數轉字串的函式不太會用,涉及到浮點數的一些操作還不是很懂。然後輸入一個名稱,找了一下它的序列號作為檢測。證明是對的。

總結下,那個neg最後還是沒去掉,然後第二個的註冊機感覺寫起來有點繁瑣,轉化成程式碼的能力有待練習吧。

最後分析過程中找到的一些資料

浮點數除法

http://scc.qibebt.cas.cn/docs/optimization/VTune(TM)%20User%27s%20Guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/instruct32_hh/vc94.htm

協處理指令

http://blog.sina.com.cn/s/blog_7753c5fa0100q96l.html

VB逆向一些常用的函式

https://www.cnblogs.com/bbdxf/p/3780187.html