Edit /etc/default/grub. Add or edit following settings.
1 2
GRUB_TIMEOUT_STYLE=hidden GRUB_TIMEOUT=1
I will also set GRUB_DEFAULT to 2, so the highlight selected default boot choice will be the 3rd option, which means Windows boot manager.
1
GRUB_DEFAULT=2
It seems everything is ready, but grub do more things. Grub checks if you have multiple systems. If more than one system was found, grub will force timeout_style to be menu. This is not what we expected.
So open /etc/grub.d/03_os-prober, and remove the last line
1
adjust_timeout
Now, run update-grub and restart.
You can see the splash image and no menu is shown. Windows boot after a brief delay.
If you want to switch back to Ubuntu, you can press Esc during that 1 second timeout to get back the boot options menu, and select a different system to boot.
We recommend using Jekyll if you want the built-in support it offers, including the GitHub Pages gem to manage dependencies, specific build failure messages, and more specific help with troubleshooting.
All downloads are full versions with just a few features locked. Use your license key to unlock complete CKFinder functionality, with no need to download a separate package. Try it for a limited period of time and buy it when you are ready. We prepared easy licensing options for your development purposes.
If You did not pay the License Fee, You may use unlicensed copies of the Software for the exclusive purpose of demonstration. In this case You will be using the Software in “demo mode”. Without derogating from the forgoing, You may not use the Software in “demo mode” for any of your business purposes. The Software in “demo mode” shall only be used for evaluation purposes and may not be used or disclosed for any other purposes, including, without limitation, for external distribution. You may not remove the demo notices, if any, from the user interface of the Software nor disable the ability to display such notices nor otherwise modify the Software. Product support, if any, is not offered for the Software in “demo mode”
var CKFinder = function () { function __internalInit(e) { return e = e || {}, e['demoMessage'] = 'This is a demo version of CKFinder 3', e['hello'] = 'Hello fellow cracker! We are really sad that you are trying to crack our application - we put lots of effort to create it. ' + 'Would you like to get a free CKFinder license? Feel free to submit your translation! http://docs.cksource.com/ckfinder3/#!/guide/dev_translations', e['isDemo'] = !0, e; } // 后面省略了
functionbreakOn(obj, propertyName, mode, func) { // this is directly from https://github.com/paulmillr/es6-shim functiongetPropertyDescriptor(obj, name) { var property = Object.getOwnPropertyDescriptor(obj, name); var proto = Object.getPrototypeOf(obj); while (property === undefined && proto !== null) { property = Object.getOwnPropertyDescriptor(proto, name); proto = Object.getPrototypeOf(proto); } return property; }
functionverifyNotWritable() { if (mode !== 'read') throw"This property is not writable, so only possible mode is 'read'."; }
var enabled = true; var originalProperty = getPropertyDescriptor(obj, propertyName); var newProperty = { enumerable: originalProperty.enumerable };
f = f || function(e) { returnfunction(t) { return e.charCodeAt(t); }; }(o(s.config.initConfigInfo.c));
继续追查 o。
1 2 3 4 5 6 7 8 9
functiono(e) { var t, n, i; for (i = '', t = '123456789ABCDEFGHJKLMNPQRSTUVWXYZ', n = 0; n < e.length; n++) i += String.fromCharCode(t.indexOf(e[n])); return o = void0, i; }
这里的 o 似乎是个一次性函数,在 return 之前它把自己给变成了 undefined(就是 void 0),似乎为了隐藏什么东西。
编译之后的 js 全是各种奇怪的闭包,我们得好好分析一下。
o 的参数是后端传来的许可证,把许可证字符串的每一字节映射一下,比如输入许可证是 'ABCD',就会返回 '\u0009\u000a\u000b\u000c'。
functione(e, t) { for (var n = 0, i = 0; i < 10; i++) n += e.charCodeAt(i); for (; n > 33; ) { var r = n.toString().split(''); n = 0; for (var o = 0; o < r.length; o++) n += parseInt(r[o]); } return n === t; }
参数 1 是许可证,参数 2 是刚刚分析的 f(10)。
n 为许可证前 10 个字符的 ASCII 码加和,然后把这个数字的每一位加和,再把结果每一位加和,直到结果小于 33,只要这个结果等于 f(10) 的话,返回值就是 true。
functiont(e, t, n) { var i = window.opener ? window.opener : window.top , r = 0 , o = i['location']['hostname'].toLocaleLowerCase(); if (0 === t) { var s = '^www\\.'; o = o.replace(newRegExp(s), ''); } if (1 === t && (o = ('.' + o.replace(newRegExp('^www\\.'), '')).search(newRegExp('\\.' + n + '$')) >= 0 && n), 2 === t) return !0; for (var a = 0; a < o.length; a++) r += o.charCodeAt(a); return o === n && e === r + -33 * parseInt(r % 100 / 33, 10) - 100 * ('' + r / 100 >>> 0); }
functione(e, n, i, r, o, s) { for (var a = window['Date'], l = 33, u = i, c = r, d = o, f = s, c = l + (u * f - c * d) % l, d = u = 0; d < l; d++) 1 == c * d % l && (u = d); c = e, d = n; var h = 10000 * (225282658 ^ t.m); return f = new a(h), 12 * ((u * s % l * c + u * (l + -1 * r) % l * d) % l) + ((u * (33 + -1 * o) - 33 * ('' + u * (l + -1 * o) / 33 >>> 0)) * c + u * i % 33 * d) % l - 1 >= 12 * (f['getFullYear']() % 2000) + f['getMonth'](); } var t = { s: function(e) { for (var t = '', n = 0; n < e.length; ++n) t += String.fromCharCode(e.charCodeAt(n) ^ 255 & n); return t; }, m: 92533269 };
functionlc(c) { var map = [1, 8, 17, 22, 3, 13, 11, 20, 5, 24, 27]; var key = '*???-*?**-?**?-*?**-*?**-?*?*-?**?'.replace(/-/g, '').split(''); for (var i = 0; i < map.length; ++i) { key[map[i]] = c[i]; } var result = []; for (var i = 0; i < key.length; i += 4) { var result_part = ''; for (var j = i; j < i + 4 && j < key.length; ++j) { result_part += key[j]; } result.push(result_part); } return result.join('-'); }
基本转换函数
1 2 3 4 5 6 7 8
functionc(f) { var map = '123456789ABCDEFGHJKLMNPQRSTUVWXYZ'; var result = ''; for (var i = 0; i < f.length; ++i) { result += map[f[i]]; } return result; }
f10 由 f0 ~ f9 生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14
functionf10(c) { var tmp = 0; for (var i = 0; i < 10; ++i) { tmp += c.charCodeAt(i); } while (tmp > 33) { var tmp1 = tmp.toString().split(''); tmp = 0; for (var i = 0; i < tmp1.length; ++i) { tmp += parseInt(tmp1[i]); } } return tmp; }
f4 与 f0 相关,分三种情况:
单域名许可证:www.example.com 和 example.com 可用
含通配符域名许可证:*.example.com 和 example.com 可用
不限制域名许可证:任意域名均可使用。
其实还有第四种,就是真正的单域名,完全匹配许可证:仅 foo.example.com 可用
单域名许可证
1
f4 = f0;
含通配符域名许可证
1
f4 = (f0 + 1) % 33; // 或 f0 = (f4 - 1 + 33) % 33;
不限制域名许可证
1
f4 = (f0 + 2) % 33; // 或 f0 = (f4 - 2 + 33) % 33;
完全匹配域名许可证
1
f4 = (f0 + 3) % 33; // 或 f0 = (f4 - 3 + 33) % 33;
如果是不限制域名许可证则不验证 f7,如果是单域名许可证或含通配符域名许可证,算法如下
1 2 3 4 5 6 7
functionf7(licenseName) { var tmp = 0; for (var i = 0; i < licenseName.length; ++i) { tmp += licenseName.charCodeAt(i); } return tmp % 100 % 33; }
其实,我没有去纠结 Y 轴正方向的问题,反正 X 轴都是向右为正方向,我就先找出 X 轴的位置,然后 Y 坐标一般都是 X 坐标偏移 4 字节嘛。
好的,装逼结束。
那我们为什么要知道坐标轴的正方向?
因为,我们不知道任何与坐标有关的信息,包括我现在在哪,移动多远是 1 单位长度。如果不确定正方向的话,我们只能使用 Changed value 和 Unchanged value 两种搜索类型。如果确定了坐标轴正向之后,就可以使用 Increased value 和 Decreased value 了,更方便找到准确的数值以及派出错误的数值。
游戏的物理引擎和绘图引擎并不是运行在同一线程上的,不同线程都不是一起运行的,他们的栈肯定也不是共用的,所以他们之间只能通过堆内存来沟通。这带给我们一个好处就是,堆内存是可以通过 CE 很方便地进行搜索的。但也带给我们一个问题就是,你修改数值的时机必须恰到好处,恰好在一个线程写入,另一个线程读取之前修改 (这里可能存在一些问题,) ,这通常在线程外是很难做到的。总之多线程技术给我们带了很多麻烦,导致我们不得不去使用代码注入。
如何搜索呢?先在空中锁定 Y 坐标,让其在空中不断下落。这是虽然人会回归原位,但是 Y 速度是一直增大的。注意,向下落的速度应该是负数,越落越快应该是速度的 Y 轴负方向越来越大,所以搜索的时候应该是搜索减小的数值,如果因为速度过大,撞到了地面上,那就再搜索增大的数值。
使用“未知初始值”搜索 Float 数据,然后配合“减小的数值”和“增大的数值”。最终剩下了几千个数值,不过不要紧,我们知道角色属性应该是一个结构体,应该存储在相邻的位置,好的,仅保留罐子坐标附近的值,然后通过锁定尝试一下。然后锁定成正数试试,锁定成负数试试。最后我们确定了,Y 速度在 Y 坐标 +14 偏移的位置,同理 X 速度也在 X 坐标 +14 偏移的位置。
What’s the fuck! 为什么又改回英文版了?前几张图片用的还是汉化版呢!
因为我发现中文版翻译水平不是很好,我用中文版的时候,有的地方突然找不到我想找的选项了。
使用上述对待 Y 坐标的方法来对待 Y 速度——首先替换成无用代码,这时 Y 速度就不变了,甚至也没法通过锤子来使自己改变 Y 速度了。只能眼睁睁地看着他 Y 方向作匀速直线运动。其实这时我们可以在 CE 中修改速度数值,因为游戏部分的代码已经不会再影响速度了,我们直接在进程外写入就可以影响游戏了。
我们想到了最前面提出的第 2 种外挂的想法,减小重力。能不能只减小重力,而不影响其他的东西。而且,与重力加速度有关的代码,一定就在写入 Y 速度的指令附近。重力加速度这个东西,我们什么都不知道,根本没法搜索(可以在末尾)
我们之前分析了引擎中可能的写法,读取 Y 速度,加上 g * Δt,然后再写回去。那么怎么办呢?首先先找到访问 Y 速度的代码 Find out what access this address。注意,是访问的代码,因为我们要找的“加上 g * Δt”的代码一定是在写入 Y 速度之前,如果只查找写入的代码的话,我们单步调试的时候想做到往前走还是很麻烦的,所以要用“访问的代码”,这样读取和写入的指令都会被记录,我们从读取的开始分析就可以了。
这里注意,必须在操作游戏的同时注意指令计数器,找到对我们有用的代码。最后我们分析得出,这两条指令的中间对 Y 速度进行了某种操作。
newmem: //this is allocated memory, you have read,write,execute access //place your code here // 在这里添加代码 cmp [ebx+10], 1 // 判断 [ebx+10] 是否为 1 je no_decrese_health // 如果相等的话,则跳转到 no_decrese_health 标签
首先这个游戏有简单的反调试,Cheat Engine 菜单 > Edit > Settings > Debugger Options,改一下设置 Debugger method: Use windows debugger,Debugger interface config: Try to prevent detection of debugger,简单粗暴的反反调试就可以了,至于 Try to prevent detection of debugger 具体做了什么暂时不太清楚,有待进一步研究。
我们可以尝试第一个实验,直接把 movq [edi],xmm2 改为 nop,右键该条指令,Replace with code that does nothing,我们发现镜头不会跟随我们了,然后我们可以对 edi 的地址用 CE 直接进行内存修改,发现镜头真的可以随数值移动,证明,edi 这个地址是有用的。
改完记得在右键 Restore with original code 还原代码
然后,就是 Find out what writes the address,可以看到,在相机不碰到天花板的时候只有一条指令写入,在碰到天花板的时候有两条写入,我们直接把第二条nop 掉。大功告成,我们可以在屋子里提高视野了。
于是我们又发现问题了,开镜、开车和观战的时候,步骤 2 中注入的代码不好使,搜索对 EDI 这个地址的写入,我们发现开镜、开车和观战的时候分别有不同的代码写入 EDI 这个地址,我们必须继续探究 EDI 这个地址到底之后被用来做什么了。