Favorite社通用和谐插件 v0.2【游戏全年龄化

插件下载:
HarmoFavo

1
2
3
4
5
6
7
v0.2[2014.2.19]
[+]全自动配置
v0.11[2014.2.19]
[+]支持Wiz Anniversary、funta支持不能……那玩意章节表比较奇葩、
[+]CG Patch
v0.1 [2014.2.3]
第一个版本

本插件理论上支持所有使用Favorite社游戏引擎的游戏、并且目前已有的3个汉化版全部支持、现在已经支持全自动和谐……您只需要将本插件释放到游戏目录并用AlphaROMdiE装载游戏即可。
使用方法:【请在使用前认真阅读!
首先确保您的游戏目录是这样的、HarmoFavo下载下去以后直接释放到游戏目录即可

上个图证明可以支持光鸟鸟、色鸟鸟也可以支持、方法看评论一楼的回复
和谐后的光鸟鸟、其他的图就不上了……那个加奈和澪的3P因为是男猪开脑洞梦到的……所以那个没辙╮( ̄▽ ̄”)╭ 顾及18R的小盆友要玩的时候要小心这个坑。


【这里为老版本的说明、不必阅读】然后打开plugin目录、创建一个文本文档命名为config、然后里面的内容是需要解析的游戏的hcb文件。【为了兼容各种汉化补丁所以没有搞成自动的、搞成自动的兼容性会降低的。然后把那个文件从游戏目录复制到plugin目录下、比如我要让星空的记忆FD汉化版和谐一下,就复制汉化后的脚本执行体hoshimemo_ehchn.bch到plugin目录然后再填写config的内容即可。如下图

然后回到游戏目录、启动AlphaROMdiE、勾选禁止转码、把游戏可执行文件拖到上面、比如汉化版是Hoshimemo_EHchn.exe、然后会生成一个快捷方式、以后从这里点进去就是和谐版的游戏啦~

和谐效果如下图

被屏蔽掉的肯定就是H图啦~

有一个误伤的没办法、后来确认了下那张CG的确是出现在某H情节里……

啧啧啧、看看这有多少H

ETC的内容还是可以全部看到的_(:з」∠)_这里一般不会有H的


吐槽时间:
_(:з」∠)_这两天戳了下Favorite的引擎、感谢AmaranthF对Favorite社游戏引擎的vm拆解……

hcb可执行体主要分成几个区域

1
2
3
4
5
6
7
8
9
10
11
———————
public functions
———————
dispatcher
———————
para jumper[optional]
———————
para code
———————
H memo code
———————

目前的做法比较简单粗暴、就是计算一下H memo code起始的地方、如果有call到这里的话直接给ret回去
插件关键代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
vector<DWORD> ChcbVM::GetNCallSequence(DWORD & offset)
{
return GetLastNCallSequenceCond(offset,0x01);
}


vector<DWORD> ChcbVM::GetLastNCallSequenceCond(DWORD & offset, BYTE bOP)
{
vector<DWORD> retVal;
DWORD ori = bin.seek(0,FILE_CURRENT);
bin.seek(offset,FILE_BEGIN);
WORD tmp1;
BYTE tmp0;
do
{
bin.read(&tmp0,1);//skip initStack
offset++;
} while (tmp0!=0x01);//从一个函数头开始反编译
bin.read(&tmp1,2);//skip initStack param
offset+=2;
for (BYTE op;;)
{
op=bin.readb();
if (op == 0x2)//native call
{
DWORD native = bin.readdw();
retVal.push_back(native);
offset+=5;
}
else if (op==0x1)
{
break;
}
else if (op==bOP)
{
retVal.clear();
offset+=vmlde(op);
}
else
{
offset+=vmlde(op);
}
}

bin.seek(ori,FILE_BEGIN);

return retVal;
}

int comp(const void* a,const void* b)
{
return *(PDWORD)a>*(PDWORD)b;
}

vector<DWORD> ChcbVM::GetNCallList(DWORD & offset)
{
auto && res = GetNCallSequence(offset);

sort(res.begin(),res.end());
vector<DWORD> retVal;
for (size_t idx = 0;idx<res.size();++idx)
{
if (*(retVal.end()-1)!=res[idx])
{
retVal.push_back(res[idx]);
}
}
return retVal;
}


DWORD ChcbVM::AnalysisPara(void)
{
auto && res = GetLastNCallSequenceCond(hdr.EntryPoint,0x7);//最后的条件跳转后的calllist
/*
22C85 jz 22C8F
22C8A call 233EC;title
22C8F call 22CB1;start
*/
DWORD offsetParaDispacher = 0;
if (res.size())
{
int idx = 1;
search0:
DWORD offset = res[idx];
auto && res2 = GetNCallSequence(offset);//for most game
if (res2.size()<=2)
{
offsetParaDispacher = *(res2.end() - 1);
}
else
{
++idx;//Wiz
goto search0;
}
}
auto && ParaList = GetNCallList(offsetParaDispacher);
return GetNextFuncOffset(*(ParaList.end() - 1));
}

typedef DWORD (__fastcall __pfnvCall)(void *unk1,DWORD unk0);

DWORD __fastcall vCall(
void *unk1,//ecx
DWORD unk0,//edx
DWORD RetAddr,
__pfnvCall pfnvCall)
{
PDWORD pvIP = PDWORD((char *)unk1+offsetvIP);
if (*pvIP>offsetLast)
{
*pvIP = offsetLast;
return offsetLast;
}
return pfnvCall(unk1,unk0);
}