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

猜你喜欢

转载自blog.csdn.net/weixin_42489582/article/details/84928089