吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4727|回复: 12
收起左侧

[Web逆向] 执行wasm2c翻译出来的c代码二

  [复制链接]
Frhvjhhv 发表于 2021-8-13 01:35
本帖最后由 Frhvjhhv 于 2022-10-3 11:25 编辑

承接上回,我们把wasm文件下载下来,然后执行wasm2c   www.wasm  -o   www.c  命令得到   www.c   和www.h文件

然后把wabt工具包里面的wasm-rt.h,wasm-rt-impl.c,wasm-rt-impl.h文件也拿出来
bf1637793fcc005fcdacb5b6f3da9ce.png
打开visualstudio,新建c++控制台项目(或者dll均可,为了方便演示我就建立=控制台项目了),然后把 www.c   和www.h,wasm-rt.h,wasm-rt-impl.c,wasm-rt-impl.h拷贝进去
b1b226b28cc4c324521a329a775bfe2.png
组成工程文件,在主文件中导入www.h头文件,如下图所示:

然后编译一下:
659e6c957f065c01163c0bdfc44f823.png
发现抱错了。其中抱错的原因是我们加载wasm的过程中有导入函数,这些导入函数被反编译成了导入符号
www.h中的符号,分为导入 (import) 符号,和导出(export)符号。js 和 wasm 交互时,import 符号是 js 提供给 wasm 使用的。而 export 符号是 wasm 提供给 js 使用的。
171217e40b1b5ff3996a9dddf7134f7.png


其中导入符号是未定义的。就是我们要自己参考js中的导入函数去在www.c文件中实现
[JavaScript] 纯文本查看 复制代码
function initSync(A) {
        var i = {
            wbg: {}
        };
        return i.wbg.__wbg_new_59cb74e423758ede = function() {
            return addHeapObject(new Error)
        }
        ,
        i.wbg.__wbg_stack_558ba5917b466edd = function(A, i) {
            var g = passStringToWasm0(getObject(i).stack, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc)
              , i = WASM_VECTOR_LEN;
            getInt32Memory0()[A / 4 + 1] = i,
            getInt32Memory0()[A / 4 + 0] = g
        }
        ,
        i.wbg.__wbg_error_4bb6c2a97407129a = function(A, i) {
            try {
                console.error(getStringFromWasm0(A, i))
            } finally {
                wasm.__wbindgen_free(A, i)
            }
        }
        ,
        i.wbg.__wbindgen_object_drop_ref = function(A) {
            takeObject(A)
        }
        ,
        i.wbg.__wbindgen_throw = function(A, i) {
            throw new Error(getStringFromWasm0(A, i))
        }
        ,
        i = loadSync(A, i).instance,
        wasm = i.export


参考上面的js代码,
__wbg_new_59cb74e423758ede是维护一个栈结构,并将err元素入栈

_wbg_stack_558ba5917b466edd 中的getObject(i).stack是取出栈里面的err元素

其中throw error的直接赋值为NULL即可
[C] 纯文本查看 复制代码
void _558ba5917b466eddZ_vii(u32 a, u32 b);

u32(*Z_wbgZ___wbg_new_59cb74e423758edeZ_iv)(void) = NULL;
void (*Z_wbgZ___wbg_stack_558ba5917b466eddZ_vii)(u32, u32) = *_558ba5917b466eddZ_vii;
void (*Z_wbgZ___wbg_error_4bb6c2a97407129aZ_vii)(u32, u32) = NULL;
void (*Z_wbgZ___wbindgen_object_drop_refZ_vi)(u32) = NULL;
void (*Z_wbgZ___wbindgen_throwZ_vii)(u32, u32) = NULL;

其中_558ba5917b466eddZ_vii函数的定义如下:
[C++] 纯文本查看 复制代码
typedef u32* wbindgen_malloc(u32 w2c_p0);
typedef u32* wbindgen_realloc(u32 w2c_p0, u32 w2c_p1, u32 w2c_p2);
int WASM_VECTOR_LEN;
int passStringToWasm0(char* A, wbindgen_malloc i, wbindgen_realloc g) {
    int B = strlen(A);
    u32  Q = i(B);
    int e = 0;
    for (e; e < B; e++) {
        int o = (int)e;
        if (127 < o)
            break;
        w2c_memory.data[Q + e] = o;
    }
    u32 Qq = g(Q, B, e);
    WASM_VECTOR_LEN = e;
    return Qq;
}
void _558ba5917b466eddZ_vii(u32 a, u32 b)
{
    int g = passStringToWasm0("error", w2c___wbindgen_malloc, w2c___wbindgen_realloc);
    int  i = WASM_VECTOR_LEN;
    (w2c_memory.data)[a + 1] = i;
    (w2c_memory).data[a + 0] = g;
}

u32(*Z_wbgZ___wbg_new_59cb74e423758edeZ_iv)(void) = NULL;
void (*Z_wbgZ___wbg_stack_558ba5917b466eddZ_vii)(u32, u32) = *_558ba5917b466eddZ_vii;
void (*Z_wbgZ___wbg_error_4bb6c2a97407129aZ_vii)(u32, u32) = NULL;
void (*Z_wbgZ___wbindgen_object_drop_refZ_vi)(u32) = NULL;
void (*Z_wbgZ___wbindgen_throwZ_vii)(u32, u32) = NULL;

其中w2c_memory.data,w2c___wbindgen_malloc,u32等等均在www.c文件中已经定义。
对于build_in符号不用管他,因为wasm2c是用gcc编译的所以我们也要用gcc来编译和调试(不要用vs,会报一大堆错)
此时已经把环境补好了,然后我们把主文件即包含main入口点的c文件引入www.h
b1b226b28cc4c324521a329a775bfe2.png


编译一下:
[Asm] 纯文本查看 复制代码
gcc -o www ConsoleApplication5.c  wasm-rt-impl.c

fddc6328722f24f4503a7342f79fd8a.png
编译通过,表明环境已经补完

接下来我们来分析一下如何调用:
我们转到www.c文件:
490fe965ef70aaadfc8e74d342a6069.png
可以看到两个静态全局变量static wasm_rt_memory_t w2c_memory;   static wasm_rt_table_t w2c_T0;  其中 w2c_memory即相当于web里面WebAssembly.Memory,w2c_T0相当于 js 中的 WebAssembly.Table.
转到wasm_rt_memory_t这个结构体的定义可以看到:
[C++] 纯文本查看 复制代码
typedef struct {
  /** The linear memory data, with a byte length of `size`. */
  uint8_t* data;
  /** The current and maximum page count for this Memory object. If there is no
   * maximum, `max_pages` is 0xffffffffu (i.e. UINT32_MAX). */
  uint32_t pages, max_pages;
  /** The current size of the linear memory, in bytes. */
  uint32_t size;
} wasm_rt_memory_t;


其中data就相当于
WebAssembly.Memory.buffer的uint8array形式。wasm_rt_memory_t还定义了其线性内存空间的大小和页数



然后我们在转到整个wasm的入口点:

[C++] 纯文本查看 复制代码
void WASM_RT_ADD_PREFIX(init)(void) {
  init_func_types();
  init_globals();
  init_memory();
  init_table();
  init_exports();
}

即调用上面这四个函数,即可实现wasm环境的初始化。这四个函数的定义均在www.c文件中。(本次直接调用即可。但是如果外部对wasm的初始化有导入函数,就要分析了,下面是对四个函数的分析)

dc27342d3f11a53484507c8e7cca013.png
init_func_types的作用是注册函数原型。
[C++] 纯文本查看 复制代码
static void init_globals(void) {
  w2c_g0 = 1048576u;
}


init_globals初始化全局变量
[C] 纯文本查看 复制代码
static void init_memory(void) {
  wasm_rt_allocate_memory((&w2c_memory), 17, 65536);
  LOAD_DATA(w2c_memory, 1048576u, data_segment_data_0, 8009);
  LOAD_DATA(w2c_memory, 1057704u, data_segment_data_1, 1);
}

init_memory及其重要。allocate_memory就是为wasm环境分配页数为17,最大大小为65536的内存空间
LOAD_DATA就是加载一些字符串或者常量向wasm的内存中。

其中data_segment_data_0的定义如下:

8d337603a56d6e9d96ee1bd32f5c507.png

他就相当于wat 的 S 表达式形式的下面字符串常量

e8800c4616ee06b3ddeb17dbc0fbfcc.png

我们来看一下 load_data的定义:

[Asm] 纯文本查看 复制代码
static inline void load_data(void *dest, const void *src, size_t n) {
  memcpy(dest, src, n);
}
#define LOAD_DATA(m, o, i, s) load_data(&(m.data[o]), i, s)
#define DEFINE_LOAD(name, t1, t2, t3) 


其四个参数分别是w2c_memory,要写入w2c_memory.data处的内存地址(注意,不是真实的内存地址,而是相对与w2c_memory.data这个uint8_t*的地址,即相对地址,也可以理解为w2c_memory.data=[1,2,3,4,4,,5,5,5],a[5]就是w2c_memory.data相对地址5处的数据) ,要写入的数据,数据长度。最终调用memcpy来把数据拷贝到内存空间中。


36779224a2991c84eb517273b194802.png

init_table初始化函数指针数组。Table 可以看成函数指针的数组,数组的每一项存放着函数的签名和函数的地址。这个数组可以放任何不同类型的函数指针,有了函数签名这信息,在函数调用的时候就可动态检查参数是否对应。wasm 可以往 Table 中放函数,js 也可以往 Table 中放函数。放置好函数之后,就可以通过 Table 的索引去间接调用。于是 wasm 和 js,只需要知道 Table 的函数索引,没有必要使用函数指针。

然后我们可以看到导出函数init_exports的定义:

[C] 纯文本查看 复制代码
static void init_exports(void) {
  /* export: 'memory' */
  WASM_RT_ADD_PREFIX(Z_memory) = (&w2c_memory);
  /* export: '__wbg_rsapublickeypair_free' */
  WASM_RT_ADD_PREFIX(Z___wbg_rsapublickeypair_freeZ_vi) = (&w2c___wbg_rsapublickeypair_free);
  /* export: 'rsapublickeypair_new' */
  WASM_RT_ADD_PREFIX(Z_rsapublickeypair_newZ_iv) = (&w2c_rsapublickeypair_new);
  /* export: 'rsapublickeypair_init' */
  WASM_RT_ADD_PREFIX(Z_rsapublickeypair_initZ_vi) = (&w2c_rsapublickeypair_init);
  /* export: 'rsapublickeypair_encode' */
  WASM_RT_ADD_PREFIX(Z_rsapublickeypair_encodeZ_viiii) = (&w2c_rsapublickeypair_encode);
  /* export: '__wbindgen_malloc' */
  WASM_RT_ADD_PREFIX(Z___wbindgen_mallocZ_ii) = (&w2c___wbindgen_malloc);
  /* export: '__wbindgen_realloc' */
  WASM_RT_ADD_PREFIX(Z___wbindgen_reallocZ_iiii) = (&w2c___wbindgen_realloc);
  /* export: '__wbindgen_free' */

  WASM_RT_ADD_PREFIX(Z___wbindgen_freeZ_vii) = (&w2c___wbindgen_free);

这里面实现了在www.h头文件中申明的导出函数。
分析之后。我们开始调用:
[C] 纯文本查看 复制代码
char gccc[1000];void Yyyyyyy() {
    init_func_types();
    init_globals();
    init_memory();
    init_table();
    init_exports();
}char* Gou(u32* text, int length)
{
    Yyyyyyy();}

首先在www.c文件中定义一个返回值为char*的函数返回加密的字符串。函数参数为待加密字符串,字符串长度,然后调用Yyyyyyy函数初始化wasm环境
[C] 纯文本查看 复制代码
    u32 aa = w2c_rsapublickeypair_new();//1176460
    w2c_rsapublickeypair_init(aa);
    u32 nei = w2c___wbindgen_malloc(length);//1176428
    int le = 0;
    for (le; le < length; le++)
    {
        w2c_memory.data[nei + le] = text[le];
    }
    //LOAD_DATA(w2c_memory, nei, text, length);
    // memcpy(&w2c_memory, text, length);
    w2c_rsapublickeypair_encode(8, aa, nei, length);

然后加密流程与js一样:rsapublickeypair_new初始化,rsapublickeypair_init初始化公钥。然后直接用w2c_memory.data[nei + le] = text[le];向wasm的内存空间中赋值。
[C] 纯文本查看 复制代码
 u32 bbb = i32_load(&w2c_memory, 8);
    u32 bb = i32_load(&w2c_memory, 12);
      #include <stdio.h>
    printf("%d\n", bbb);
    printf("%d\n", i32_load(&w2c_memory, 12));
    // char* src;
    
     //src= (char*)malloc((int)bb);
    for (int i = 0; i < (int)bb; i++)
    {
        //printf("%c", w2c_memory.data[bbb + i]);
        gccc[i] = w2c_memory.data[bbb + i];
       // src[i] = (char)(w2c_memory.data[bbb + i]);
    }
    w2c___wbindgen_free(bbb, bb);

    return gccc;

这里用i32_load(&w2c_memory, 12);直接取出内存处12的值。同样取出内存处为8的值,然后打印出这两个值然后取出内存处bbb,长度为bb的字符串即可。。在www.h头文件中导出函数 extern char* Gou(char*, int);然后在主程序mian函数中调用Gou函数:
[C] 纯文本查看 复制代码
int main()
{
    const int length = 12;
    char* str = "666666890ftt";
    u32 cc[12];
    for (int i = 0; i < length; i++)
    {
        cc[i] = (u32)(str[i]);
    }
    //Gou(cc, 6);
   // printf("%s\n", cc);
    char* ccc;
    //int ccc;
    ccc = Gou(cc, length);
    printf("%s", ccc);
    //free(ccc);
    getch();
}

我们输入字符串666666890ftt,返回加密结果


现在来编译一下:
[Asm] 纯文本查看 复制代码
gcc -o www ConsoleApplication5.c wasm-rt-impl.c  www.c

802159ad12713f916cbe02e160d38bb.png
编译成功,然后运行一下,返回了字符串fb32ca7c2863964f2438fa50a50d8e3f
846d6034718e349a3d674e6a67e880e.png
返回了加密结果
打开之前爬取的html,输入加密字符串,验证一下:
08f8e7f569db3387af7d493aa371669.png

正确。至此就结束了。我们可以写出c++   dll供其他语言调用。
参考:执行wasm转换出来的c代码https://zhuanlan.zhihu.com/p/43986042

免费评分

参与人数 13吾爱币 +21 热心值 +10 收起 理由
很快再相见123 + 1 + 1 我很赞同!
root233 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
xiaoyang56 + 1 我很赞同!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
SHASHA2021 + 1 + 1 谢谢@Thanks!
19511626267 + 1 + 1 热心回复!
lyk1115 + 1 我很赞同!
fjzry + 1 + 1 我很赞同!
漁滒 + 3 我很赞同!
slayercat + 1 我很赞同!
涛之雨 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
逍遥一仙 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
helian147 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

daolaji 发表于 2021-8-13 07:24
我是初学者先来学习学习
hjsaiyy 发表于 2021-8-13 07:36
Eaglecad 发表于 2021-8-13 08:00
timeni 发表于 2021-8-13 08:34
学到了,谢谢分享
Light紫星 发表于 2021-8-13 10:12
高手,之前用ida分析代码的时候,扣c代码出来要调试很久,这个直接改改就能编译了,厉害
JWL213312 发表于 2021-8-13 15:02
谢谢分享,先学习学习
JWL213312 发表于 2021-8-13 15:04

学到了,谢谢分享
vnkgt 发表于 2021-8-13 15:56
不大懂,但大为震惊
ccxxss 发表于 2021-8-13 17:13
学习学习,继续努力
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-3-29 16:10

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表