首页
论坛
课程
招聘
[原创]菜鸟第一次DIY, 为你的软件加载皮肤
2010-1-2 02:59 17405

[原创]菜鸟第一次DIY, 为你的软件加载皮肤

2010-1-2 02:59
17405
【文章标题】: 菜鸟第一次DIY, 为你的软件加载皮肤
【文章作者】: blueapplez
【作者邮箱】: blueapple1987@163.com
【软件名称】: War3 改键工具  1.02
【下载地址】: 附件
【操作平台】: Windows XP SP2
【完成时间】:2010-1-2 2:58:11
【文章链接】:http://bbs.pediy.com/showthread.php?p=737611
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
今晚刚修改了不久之前做的一个 War3 改键工具,看了安静a 发的一篇求助帖《如何给一个写好的软件加个皮肤!》,后来有人回复说加载一些开源的皮肤库就行了,于是我就动手DIY我的刚完成的小作品了!
【详细过程】
(一)        找到一个Appface的一个开源库,查了一下里面的调用过程,以前我用的时候是用静态库这样用
SkinStart(_T("Skin\\sap_af.urf"),WINDOW_TYPE_VC,"",GTP_LOAD_FILE,NULL,NULL);

然后我修改了一下动态加载他,并且把参数 和宏都替换掉
	typedef BOOL   (__stdcall *APPFACE_START)(char*,int,char*,int,DWORD,char*) ;
	
	HMODULE hDll = LoadLibrary("1.dll");
	if (hDll != NULL)
	{
		APPFACE_START fun = (APPFACE_START)GetProcAddress(hDll, "SkinStart");
		if (fun != NULL)
		{
			fun(_T("1.urf"),1,"",1,NULL,NULL);
		}
	}

测试一下通过!
(二)        用之前学过的PE文件格式的知识,为我的小软件增加一个Section区段,设置属性为可读可写可执行,增加Section段的C++代码如下:
新增一个Section。
首先,我们需要在PE头内找到NumberOfSections,使之加1。
然后,在文件末尾增加一个新的空间,假设为200h,记住起始行到PE文件首部的偏移。假如这个值是00034500h。同时将PE头内的SizeOfImage的值加200h。
然后,找到PE头内的Section头部。通常在Section头部结束到Section数据部分开始间会有一些空间,找到Section头部的最后然后加入一个新的头部。假设最后一个Section头部的数据是:
Virtual offset : 34000h
Virtual size : 8E00h
Raw offset: 2F400h
Raw size : 8E00h
而文件对齐和Section对齐的数据分别是:
Section Alignment : 1000h
File Alignment : 200h
那么新增加的Section必须与最后一个Section的边界对齐。它的数据分别:
Virtual offset : 3D000h (因为最后一个Section的最后边界是34000h + 8E00h = 3CE00h,加上Section对齐,则Virtual offset的值为3D000h)。
Virtual size : 200h。
Raw offset: 00034500h。
Raw size: 200h.
Characteristics : E0000060 (可读、可写、可执行)。这地方最好用windows提供的宏定义来设定IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE
6. 最后,只需要修改一下PE头内的SizeOfCode和SizeOfInitialishedData两个字段,分别加上200h。
(上面这段介绍是我抄来的,出处已经找不到了,- -!)
需要注意的问题是 修改过后的PE的入口地址是我们新添加上的Section段的Virtual offset + ImageBase,也就是修改完PE文件是不能执行的,需要你先记下他之前的入口点,然后用OD加一个jmp跳回去就ok了

下面代码:
//Get the alignment Address
DWORD Alignment(DWORD dwValue, DWORD dwDuiQ)
{
while(dwValue % dwDuiQ != 0)
{
dwValue++;
}
return dwValue;
}

//Modify the PE file, include Add new Section and sth else
DWORD SetPeInfo(void *ImageOfPe, DWORD dwFileSize, DWORD dwOffset)
{
WORD NumOfSection=0;
DWORD RawOfEntryPoint=0;
DWORD AddressOfEntryPoint=0;

PIMAGE_DOS_HEADER   pDosHead=NULL;
PIMAGE_NT_HEADERS   pNtHead=NULL;
PIMAGE_SECTION_HEADER pSectionHead=NULL;
pDosHead=(PIMAGE_DOS_HEADER)ImageOfPe;
pNtHead=(PIMAGE_NT_HEADERS)((unsigned char *)pDosHead+pDosHead->e_lfanew);

//Record the old PE EnterPoint, we will modify it later.
AddressOfEntryPoint=pNtHead->OptionalHeader.AddressOfEntryPoint;
//Record the number of the section segment, we will modify it later.
NumOfSection=pNtHead->FileHeader.NumberOfSections;
//the first section's address
pSectionHead=(PIMAGE_SECTION_HEADER)((unsigned char *)pNtHead+
sizeof(pNtHead->Signature)+sizeof(IMAGE_FILE_HEADER)+
pNtHead->FileHeader.SizeOfOptionalHeader);

//Get The Last Section Pointer
PIMAGE_SECTION_HEADER pLastSection = (IMAGE_SECTION_HEADER *)((DWORD)pSectionHead + sizeof(IMAGE_SECTION_HEADER)*(NumOfSection-1));
IMAGE_SECTION_HEADER imageSectionInsert;
memset(&imageSectionInsert, 0, sizeof(IMAGE_SECTION_HEADER));
//Write sth to the new Section
//set a name for the new section
memcpy(imageSectionInsert.Name, ".blue", sizeof(".blue"));
imageSectionInsert.Misc.VirtualSize = 0x200;
imageSectionInsert.VirtualAddress = Alignment(pLastSection->VirtualAddress + pLastSection->Misc.VirtualSize, 0x1000);
imageSectionInsert.SizeOfRawData = 0x200;
imageSectionInsert.PointerToRawData = dwFileSize + dwOffset;

//Set Characteristics to read write and execute.
imageSectionInsert.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE ;
//the add 1, in fact add a sizeof IMAGE_SECTION_HEADER
memcpy(pLastSection + 1, &imageSectionInsert, sizeof(IMAGE_SECTION_HEADER));

//1.Modify the PE Entrypoint
pNtHead->OptionalHeader.AddressOfEntryPoint = imageSectionInsert.VirtualAddress;
//2.Add the number of section segment
pNtHead->FileHeader.NumberOfSections++;
//3.Add 0x200 to SizeofImage
pNtHead->OptionalHeader.SizeOfImage += 0x200;
//4.Add 0x200 to SizeOfCode
pNtHead->OptionalHeader.SizeOfCode += 0x200;
//5.Add 0x200 to SizeOfInitialishedData
pNtHead->OptionalHeader.SizeOfInitializedData += 0x200;

//return the new EntryPoint and the ImageBase.
return AddressOfEntryPoint + pNtHead->OptionalHeader.ImageBase;
}

void CMyDlg::OnOK() 
{
DWORD dwFileSize = 0;
HANDLE hFile = ::CreateFile("a.exe", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return ;
}
dwFileSize = GetFileSize(hFile, NULL);
if (dwFileSize == 0)
{
return;
}
char *szpPE = new char [dwFileSize];
memset (szpPE, 0, dwFileSize);
DWORD dwRead = 0;
ReadFile(hFile, szpPE, dwFileSize, &dwRead, NULL);
if (dwRead != dwFileSize)
{
return ;
}
CloseHandle(hFile);

//Set PE Info
DWORD dwOffset = Alignment(dwFileSize, 0x200) - dwFileSize;
DWORD dwEnterLastPoint = SetPeInfo(szpPE, dwFileSize, dwOffset);

//Add 200 Bytes and create a new file
hFile = ::CreateFile("b.exe", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return ;
}
BYTE *sz200Size = new BYTE[0x200 + dwOffset];
memset(sz200Size, 0, 0x200+dwOffset);
//    [COLOR="Red"]Write binary codes here, but do not forget jmp to the old EntryPoint.[/COLOR]
//     sz200Size[dwOffset] = 0xe9;
//     sz200Size[dwOffset+1] = 0xbb;
//     sz200Size[dwOffset+2] = 0x7b;
//     sz200Size[dwOffset+3] = 0xFF;
//     sz200Size[dwOffset+4] = 0xFF;

//set the file size
SetFilePointer(hFile, dwFileSize + dwOffset + 0x200, NULL, FILE_BEGIN);
//set file to the start position
SetFilePointer(hFile, NULL, NULL, FILE_BEGIN);
DWORD dwFeiWu = 0;
//write modified szpPE info to new file.
WriteFile(hFile, szpPE, dwFileSize, &dwFeiWu, NULL);
//write the 0x200 section code to new file, do not forget the offset file size.
WriteFile(hFile, sz200Size, dwOffset + 0x200, &dwFeiWu, NULL);
CloseHandle(hFile);

//release the memory we used.
delete [] sz200Size;
delete [] szpPE;
}

        好了修改一下,在新入口点加一个jmp original Address,保存,能正常运行,ok,进行下一步。
    PS:这段代码是我查阅相关资料写出来的,文件处理的不好,最好用文件映射来做,对有些PE文件就会失效,我不知道为什么,期待有人来解释解释是为什么。
(三)       
下面开始加载我们的皮肤库了,用OD载入,从第二步最后加的jmp 开始修改
00436000 >  60              pushad                                   ; 这是新增Section段的开始
00436001    68 36604300     push    00436036                         ; ASCII "1.dll"
00436006    E8 70BD3C7C     call    kernel32.LoadLibraryA
0043600B    68 3D604300     push    0043603D                         ; ASCII "SkinStart"
00436010    50              push    eax
00436011    E8 1A4E3D7C     call    kernel32.GetProcAddress
00436016    6A 00           push    0
00436018    6A 00           push    0
0043601A    6A 01           push    1
0043601C    68 58604300     push    00436058                        ; [COLOR="Blue"]这个地方我也没搞懂[/COLOR]
00436021    6A 01           push    1
00436023    68 48604300     push    00436048                         ; ASCII "1.urf"
00436028    FFD0            call    eax
0043602A    61              popad
0043602B  - E9 6247FDFF     jmp     0040A792                         ; 跳到原来的入口点执行
00436030    0000            add     byte ptr [eax], al
00436032    0000            add     byte ptr [eax], al
00436034    0000            add     byte ptr [eax], al
00436036    312E            xor     dword ptr [esi], ebp             ; 字符串 1.dll
00436038    64:6C           ins     byte ptr es:[edi], dx
0043603A    6C              ins     byte ptr es:[edi], dx
0043603B    0000            add     byte ptr [eax], al
0043603D    53              push    ebx                              ; 字符串 SkinStart
0043603E    6B69 6E 53      imul    ebp, dword ptr [ecx+6E], 53
00436042    74 61           je      short 004360A5
00436044    72 74           jb      short 004360BA
00436046    0000            add     byte ptr [eax], al
00436048    312E            xor     dword ptr [esi], ebp             ; 字符串 1.urf
0043604A    75 72           jnz     short 004360BE
0043604C    66:0000         add     byte ptr [eax], al
0043604F    0000            add     byte ptr [eax], al
00436051    0000            add     byte ptr [eax], al
00436053    0000            add     byte ptr [eax], al
00436055    0000            add     byte ptr [eax], al
00436057    0000            add     byte ptr [eax], al
00436059    0000            add     byte ptr [eax], al


0043601C    68 58604300     push    00436058                        ; 这个地方我也没搞懂,之所以这么做,是我把之前写的那段c++代码用OD看了一下 发现他push进去了一个数据全是0000的地址,我只好照做,push 0 不行,不太懂这个地方

保存,哈哈 ,看看效果,很一般啊!可以换一些漂亮 urf文件,直接替换就ok,版本不一致就不能保证了!


--------------------------------------------------------------------------------
【版权声明】: 文章发自看雪论坛,转载请注明作者并保持文章的完整, 谢谢!

                                                       2010年1月2日 3:10:11

[2022冬季班]《安卓高级研修班(网课)》月薪两万班招生中~

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (22)
雪    币: 295
活跃值: 活跃值 (150)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
blueapplez 活跃值 14 2010-1-2 03:27
2
0
又从官网上下了皮肤,试了试效果 依然不理想!!
上传的附件:
雪    币: 173
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
安静a 活跃值 2010-1-2 16:15
3
0
嘿嘿 感谢你了 我也学习下 !不会的在问你!
雪    币: 474
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
feierin 活跃值 2010-1-2 16:50
4
0

楼主好强
那个WAR3显血改键的工具源码能发出来学习下吗?
雪    币: 295
活跃值: 活跃值 (150)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
blueapplez 活跃值 14 2010-1-2 17:32
5
0
War3Key源码.rar

PS:0043601C    68 58604300     push    00436058 的意思是将一个NULL字符串参数入栈,其实push 0 也是对的,重新试验过了  呵呵!
上传的附件:
雪    币: 2984
活跃值: 活跃值 (247)
能力值: ( LV15,RANK:1395 )
在线值:
发帖
回帖
粉丝
lacoucou 活跃值 12 2010-1-3 12:39
6
0
这个能不能加载别的格式的皮肤文件
雪    币: 295
活跃值: 活跃值 (150)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
blueapplez 活跃值 14 2010-1-3 15:12
7
0
If the Appface dll support it, U can!
雪    币: 204
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tonydong 活跃值 2010-1-4 14:32
8
0
学习了。。。 感谢。
雪    币: 124
活跃值: 活跃值 (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ouyangtian 活跃值 2010-1-4 23:58
9
0
新手膜拜!!
雪    币: 211
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kissoks 活跃值 2010-1-5 08:55
10
0
不错,学习了~~~~~~~~~~
雪    币: 2273
活跃值: 活跃值 (25)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
北极狐狸 活跃值 7 2010-1-6 08:32
11
0
GoodJob,O(∩_∩)O~膜拜一下.
我想可以用shellcode做,参照HOOK的做法,做成一个补丁。应该会更有效果。
楼主可以做一个上来,给大家分享一下。
雪    币: 295
活跃值: 活跃值 (150)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
blueapplez 活跃值 14 2010-1-6 10:24
12
0
谢谢版主鼓励,待我查查相关资料 再搞
雪    币: 270
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
SIsIa 活跃值 2010-1-12 00:07
13
0
没有失误之处,我不赐教了额
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
热火朝天 活跃值 2010-1-12 01:00
14
0
这个我倒是遇到一个不能加载的,学习一下
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
徐浩 活跃值 2010-1-13 15:55
15
0
学习学习
看明白一点
雪    币: 1223
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
吃肉不胖 活跃值 2010-1-18 23:35
16
0
青岛的高手啊
雪    币: 65
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
langker 活跃值 2010-3-14 12:51
17
0
奇怪了,我这里last.exe文件居然运行不起来,另外两个程序的皮肤也没有变,不知道这是不是跟系统有关?
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ylecxm 活跃值 2010-3-15 13:00
18
0
以前也加载过别人的皮肤,不过还是不太明白,尤其是皮肤的制作
雪    币: 247
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
insectzl 活跃值 2010-3-18 22:09
19
0
虽然不会玩这个也没玩过,但一定要学,要了解。
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秦勿曰 活跃值 2010-4-13 22:41
20
0
学习 正要研究相关的知识~
雪    币: 118
活跃值: 活跃值 (13)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
olydbg 活跃值 1 2010-4-13 23:00
21
0
学习。。 好东西
雪    币: 61
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
niuxuexin 活跃值 2010-7-25 13:45
22
0
记录下来,看看看看
雪    币: 67
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
楠瓜 活跃值 2010-7-25 15:58
23
0
这个值得学习下
游客
登录 | 注册 方可回帖
返回