Git Product home page Git Product logo

blog's People

Contributors

hackwaly avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

blog's Issues

逆向《放置江湖》的记录

申明:仅出于学习目的,如有侵权请通知我,我会立即删除。他人不得将此文中信息用于商业目的。

首先网上找了一下其他人是否有分享逆向《放置江湖》的经验,找到了这个 https://github.com/crazyyao0/codearchive/tree/master/reverse/%E6%94%BE%E7%BD%AE%E6%B1%9F%E6%B9%96

大概意思《放置江湖》应该是cocos2d-x写的,里面的数据和逻辑都在lua文件里。发布出来的apk里面打包进去的lua文件是加密过的,需要解密。作者是自己写的解密脚本,我比较懒,网上找了下看看有没有现成的。找到 https://github.com/lyzz0612/cocos_decrypt

这个脚本解密是全自动的,不过在识别 sign 和 key 的时候遇到了点问题。所幸它支持手动传 sign 和 key,网上也找到了如何寻找 cocos2d-x 加密的 sign 和 key:https://blog.csdn.net/u012278016/article/details/79607356

由于只需要破解一次,所以我没有去改进那个解密脚本,而是手动找出 sign 和 key 之后对 apk 做了解密。解密的过程中有点意外,解密脚本硬编码了需要解密的文件的后缀名为 .luac,在《放置江湖》中,后缀名为 .lua,所以需要调整下解密脚本。

解密完成后,提取出来的 *.lua 文件依然是二进制的,用 winhex 和未解密的版本作了下对比。发现文件是不一样的,这说明解密是完成了的,只不过解密出来的可能是 lua 的 bytecode,需要咱们反编译一下。

解密之后的 lua 文件在 winhex 下明显前四个字符是可见字符,应该是文件格式的 magic。显示为” LJ “,hex 为 “1B4C4A02“,猜测是 luajit 的 bytecode,通过搜索确认了我的猜测。于是开始搜索 luajit 的 decompiler。找到 https://gitlab.com/znixian/luajit-decompiler 应该是目前还在维护的版本。

反编译过程会出现很多 warning 和 exception,应该是 decompiler 不够完善导致的。不过不影响记录数据的 lua 文件的反编译。

image

由于我是比较懒的人,所以我比较乐意节省那些和我同样懒并且有着同样爱好的人的时间:
https://gist.github.com/hackwaly/3a7d6caeb50388c7b625c04105a39d60

一种解决引用计数在并发环境下低效的思路

引用计数在并发环境下,由于需要考虑并发问题,通常会引入原子操作,降低了引用计数的性能。
一种思路:
假定我们的编程语言的并发范式是 actor。
那么我们在讲一个可回收对象 send 到别的 actor 中去的时候,可以在那个 actor 下对这个对象单独进行计数。而原来的 actor 里的计数给它加一。当另外那个 actor 里的计数等于 0 的时候,才跨线程去更新原来 actor 里的计数减一,这样极大的减少了并发操作的次数,并且也不需要在计数上搞原子操作了。利用 actor 的消息队列就行了。

An approach to implement async/await in Javascript with nearly zero overhead

Consider this Javascript, executed in chrome in 2775.01ms on my MBP (please close devtools first before you test it). Why? Because under the hood ES7 use promise to implement await/async, which introduce massive overhead. Call an async function is doggy slow even if it actually doesn't do any async thing.

image

function sleep(t) {
    return new Promise((resolve) => {
        setTimeout(resolve, t);
    });
}
async function small(i, n) {
    if (i === Math.floor(n / 2)) {
        await sleep(1000);
    }
}
async function test(n) {
    let t = performance.now();
    for (let i = 0; i < n; i++) {
        await small(i, n);
    }
    console.log(performance.now() - t);
}
test(5000000);

Now, I'll present you a novel approach to implement async/await. It combines CPS, state machine and exception to reconstruct call stack and avoid closure creation.

The javascript above then can transform to the javascript below. You can test it in your chrome. I'll explain it next time. These code is just prototype for proof. You don't need handwrite your async logic like these. There will be some compilers do it. Thank you!

image

function GetContinuation(callback, outerState) {
    this.callback = callback;
    this.stack = [];
    this.outerState = outerState;
}

function makeContinuation(stack, index) {
    if (index === stack.length) {
        return function () {};
    }
    let func = stack[index];
    let args = stack[index + 1];
    let parent = makeContinuation(stack, index + 2);
    return function () {
        return func.apply(parent, args);;
    };
}

function bind(func, this_, args) {
    return function () {
        return func.apply(this_, args);
    };
}

function callcc(callback, outerState) {
    throw new GetContinuation(callback, outerState);
}

function sleep(timeout, outerState) {
    return callcc(function (continuation) {
        setTimeout(continuation, timeout);
    }, outerState);
}

function small(i, n, outerState) {
    try {
        if (i === Math.floor(n / 2)) {
            sleep(1000, 0);
        }
    } catch (exn) {
        if (exn instanceof GetContinuation) {
            exn.stack.push(small_async, [exn.outerState, i, n]);
            exn.outerState = outerState;
        }
        throw exn;
    }
}

function small_async(state, i, n) {
    try {
        while (true) {
            switch (state) {
            case 0:
                return this();
            }
        }
    } catch (exn) {
        if (exn instanceof GetContinuation) {
            return exn.callback(bind(small_async, this, [exn.outerState, i, n]));
        }
        throw exn;
    }
}

function test(n, outerState) {
    var i;
    var t;
    try {
        t = performance.now();
        i = 0;
        while (i < n) {
            small(i, n, 0);
            i ++;
        }
        console.log(performance.now() - t);
    } catch (exn) {
        if (exn instanceof GetContinuation) {
            exn.stack.push(test_async, [exn.outerState, t, i, n]);
            exn.outerState = outerState;
        }
        throw exn;
    }
}

function test_async(state, t, i, n) {
    try {
        while (true) {
            switch (state) {
            case 0:
                i++;
            case 1:
                if (i >= n) {
                    state = 2;
                    continue;
                }
                small(i, n, 0);
                continue;
            case 2:
                console.log(performance.now() - t);
                return this();
            }
            
        }
    } catch (exn) {
        if (exn instanceof GetContinuation) {
            return exn.callback(bind(test_async, this, [exn.outerState, t, i, n]));
        }
        throw exn;
    }
}

function main() {
    test(5000000, 0);
}

function exec(main) {
    var task;
    task = main;
    while (true) {
        try {
            return task();
        } catch (exn) {
            if (exn instanceof GetContinuation) {
                task = function () {
                    return exn.callback(makeContinuation(exn.stack, 0));
                };
            } else {
                throw exn;
            }
        }
    }
}
exec(main);

我的实现 GC 的思路

1,每个gcref指向的struct的第一个(或-1个)字段,保存类型的metadata,里面有记录struct里哪些字段是gcref,以及他们的位置(最好是挨着放一起,这样记录下开始位置和数量就ok了)。

2,stack 里将 gcref 类型的变量,全部挨着放在一起叫 gcref stack。stack里在最前面保存一个 gcref stack中gcref的数量。gcref stack预留好寄存器里gcref在发生gc时要spill到gcref stack里的位置。

3,不搞 gc 的yield point了。也就是不在函数的进入或者退出的地方、循环的back edge前面等这些地方加判断是否需要 gc。而是通过外部线程暂停需要gc的线程,拿到pc,根据预先记录好的信息,计算出哪些寄存器是gcref,将它们存到栈上预留的gcref stack上。然后扫描stack就简单了。

4,stack 上预留给寄存器gcref的空间,不用每个frame都预留,只需要最里层的frame留就行了。那么这样依赖,gcref stack最好是放在栈顶。并且不要函数内支持动态扩展栈

5,把数据类型分为几大类:是否mutable,是否sendable,是否不可能含循环引用。针对特定的类型进行特定的gc方式。比如说 immutable + cyclic 可以用 traced gc。mutable + non-cyclic 可以用引用计数。mutable + sendable 可以从语言层面上搞成像js里transferable那样的。

6,no-escape的数据可以直接分配在栈里

React 有毒

我接触 React 的时候它才刚发布,但我完全想象不到 React 会发展到现在这样火。现在各种 React 的介绍文章,也不用我多废话 React 是一个什么样的东西了。

我这里只想泼一泼冷水,说一说 React 不太好的地方:

  1. 另立标准,这个真的很讨人厌。不光是 classNamehtmlFor,驼峰化的属性,还不支持命名空间属性。既不是 HTML,也不是 XML。你不能直接复制使用 HTML 代码了,这加重了用户的负担。
  2. 组件只支持实际 DOM 零个或者一个节点,不支持多个节点。这个限制导致你很多时候在做组件抽象的时候不得不引入没必要的包裹节点. 实际上,目前你没办法用 JSX 语法表达一个 DocumentFragment.。相关 Issue facebook/react#2127
  3. 函数式看上去很美,用起来很方便,但是性能是真差。React 官方说现代浏览器这点性能损失相对于 DOM 更新可以忽略,但实际上它的渲染模型在很多情形下是低效的。就连它最擅长的组件化,也因此只能避开布局功能。你可以想象一下用 React 写的带布局功能的组件系统,在 resize 的时候会有多低效(这里发现一个demo https://rawgit.com/jvanderberg/react-box-layout/master/demo/demo1.html )。
  4. 一些其他很丑陋的地方,比如说生成的 react-id 。还有你去看 React 更新日志的话,你会看到这个版本新支持了什么事件,有一个新版本支持了什么事件。这些东西为什么不提供扩展能力,反而让开发者受制于 React。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.