huan / sidecar

Easily hook/call binary functions using ES6 class with TypeScript annotation (Powered by Frida)
https://npmjs.com/package/sidecar
Apache License 2.0
47 stars 6 forks source link

designParamTypeList in @ParamType is undefined? #26

Open jwwang2003 opened 2 years ago

jwwang2003 commented 2 years ago
@Hook(agentTarget('hookLogoutEventCallback'))
  logoutEvent (
    @ParamType('int32', 'U32') bySrv: number,
  ) { return Ret(bySrv) }

The @ParamType causes the following error:

D:\编程\github\wechat-hook\node_modules\sidecar\src\decorators\param-type\guard-param-type.ts:26
  const designParamType = designParamTypeList[parameterIndex] 
                                             ^
TypeError: Cannot read properties of undefined (reading '0')
    at guardParamType (D:\编程\github\wechat-hook\node_modules\sidecar\src\decorators\param-type\guard-param-type.ts:26:46) 
    at paramTypeDecorator (D:\编程\github\wechat-hook\node_modules\sidecar\src\decorators\param-type\param-type.ts:48:19)   
    at D:\编程\github\wechat-hook\src\index.ts:9:37
    at DecorateProperty (D:\编程\github\wechat-hook\node_modules\reflect-metadata\Reflect.js:553:33)
    at Reflect.decorate (D:\编程\github\wechat-hook\node_modules\reflect-metadata\Reflect.js:123:24)
    at __decorate (D:\编程\github\wechat-hook\src\index.ts:4:92)
    at Object.<anonymous> (D:\编程\github\wechat-hook\src\index.ts:38:3)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Module.m._compile (D:\编程\github\wechat-hook\node_modules\ts-node\src\index.ts:1475:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1155:10)
[nodemon] app crashed - waiting for file changes before starting...

If I don't include @ParamType , the application works without any errors.

huan commented 2 years ago

Would appreciate it if you can provide more information or a minimum code with reproducible steps.

jwwang2003 commented 2 years ago

The init-agent-script file

console.log('Hello from init-agent-script')

//3.3.0.115
const offset = {
  node_offset: 0x1db9728,
  handle_offset: 0xe4,
  send_txt_call_offset: 0x3e3b80,
  hook_point: 0x40d3b1,
  chatroom_node_offset: 0xb08,
  nickname_offset: 0x1ddf534,
  wxid_offset: 0x1ddf4bc,
  head_img_url_offset: 0x1ddf7fc,
  is_logged_in_offset: 0x1DDF9D4,
  hook_on_login_offset: 0x51B790,
  hook_on_logout_offset: 0x51C2C0,
  hook_get_login_qr_offset: 0x4B6020,
  hook_check_login_qr_offset: 0x478B90,
  hook_save_login_qr_info_offset: 0x3DB2E0,
  get_login_wnd_offset: 0x1DB96A4,
  get_qr_login_data_offset: 0x282160,
  get_qr_login_call_offset: 0x286930,
  send_picmsg_call_offset1: 0x5ccb50,
  send_picmsg_call_offset2: 0x6f5c0,
  send_picmsg_call_offset3: 0x3e3490,
  send_attatch_call_offset1: 0x5ccb50,
  send_attatch_call_offset2: 0x5ccb10,
  send_attatch_call_offset3: 0x5ccb50,
  send_attatch_call_offset4: 0x5ccb50,
  send_attatch_call_offset5: 0x074c90,
  send_attatch_call_offset6: 0x2e2720,
  send_attatch_call_para: 0x19a7350,
  chatroom_member_nick_call_offset1: 0x558cb0,
  chatroom_member_nick_call_offset2: 0x3b0fe0,
  chatroom_member_nick_call_offset3: 0x55f6e0,
  chatroom_member_nick_call_offset4: 0x34cb10,
};
//3.3.0.115

/*------------------global-------------------------------------------*/
const availableVersion = 1661141107 ////3.3.0.115
const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll')
const moduleLoad = Module.load('WeChatWin.dll')
let currentVersion = 0

let nodeList = []  //for contact
let contactList = [] //for contact

let chatroomNodeList = [] //for chatroom
let chatroomMemberList = []//for chatroom
let loggedIn = false

const hookLogoutEventCallback = (() => {
  const nativeCallback = new NativeCallback(() => { }, 'void', ['int32'])
  const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32'])

  Interceptor.attach(moduleBaseAddress.add(offset.hook_on_logout_offset), {
    onEnter: function (args) {
      const bySrv = args[0].toInt32()
      console.log(bySrv)
      return bySrv
      setImmediate(() => nativeativeFunction(bySrv))
    }
  })
  return nativeCallback
})()

const getMyselfInfoFunction = (() => {

  let ptr = 0
  let wx_code = ''
  let wx_id = ''
  let wx_name = ''
  let head_img_url = ''

  wx_id = readString(moduleBaseAddress.add(offset.wxid_offset))
  wx_code = wx_id

  wx_name = readString(moduleBaseAddress.add(offset.nickname_offset))
  head_img_url = readString(moduleBaseAddress.add(offset.head_img_url_offset))

  const myself = {
    id: wx_id,
    code: wx_code,
    name: wx_name,
    head_img_url: head_img_url,
  };

  return JSON.stringify(myself)

})

const callLoginQrcodeFunction = ((forceRefresh = false) => {
  const json = getQrcodeLoginData()
  console.log(json)
  if (!forceRefresh && json.uuid) {
    return
  }

  const callAsm = Memory.alloc(Process.pageSize)
  const loginWnd = moduleBaseAddress.add(offset.get_login_wnd_offset).readPointer()

  Memory.patchCode(callAsm, Process.pageSize, code => {
    var cw = new X86Writer(code, { pc: callAsm })
    cw.putPushfx();
    cw.putPushax();

    cw.putMovRegAddress('ecx', loginWnd)
    cw.putCallAddress(moduleBaseAddress.add(offset.get_qr_login_call_offset))

    cw.putPopax()
    cw.putPopfx()
    cw.putRet()
    cw.flush()
  })

  const nativeativeFunction = new NativeFunction(ptr(callAsm), 'void', [])
  nativeativeFunction()
})

const getQrcodeLoginData = () => {
  const getQRCodeLoginMgr = new NativeFunction(moduleBaseAddress.add(offset.get_qr_login_data_offset), 'pointer', [])
  const qlMgr = getQRCodeLoginMgr()
  console.log(qlMgr)
  const json = {
    status: 0,
    uuid: '',
    wxid: '',
    avatarUrl: '',
  }

  if (!qlMgr.isNull()) {
    json.uuid = readString(qlMgr.add(8))
    json.status = qlMgr.add(40).readUInt()
    json.wxid = readString(qlMgr.add(44))
    json.avatarUrl = readString(qlMgr.add(92))
  }
  return json
}

const readString = (address) => {
  return readStringPtr(address).readUtf8String()
}

const readStringPtr = (address) => {
  const addr = ptr(address)
  const size = addr.add(16).readU32()
  const capacity = addr.add(20).readU32()
  addr.ptr = addr
  addr.size = size
  addr.capacity = capacity
  if (capacity > 15 && !addr.readPointer().isNull()) {
    addr.ptr = addr.readPointer()
  }
  addr.ptr._readCString = addr.ptr.readCString
  addr.ptr._readAnsiString = addr.ptr.readAnsiString
  addr.ptr._readUtf8String = addr.ptr.readUtf8String
  addr.readCString = () => { return addr.size ? addr.ptr._readCString(addr.size) : '' }
  addr.readAnsiString = () => { return addr.size ? addr.ptr._readAnsiString(addr.size) : '' }
  addr.readUtf8String = () => { return addr.size ? addr.ptr._readUtf8String(addr.size) : '' }

  // console.log('readStringPtr() address:',address,' -> str ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity)
  // console.log('readStringPtr() str:' , addr.readUtf8String())
  // console.log('readStringPtr() address:', addr,'dump:', addr.readByteArray(24))

  return addr
}

The main index.ts file

import fs from 'fs'
import path from 'path'
import {
  Sidecar,
  SidecarBody,
  Call,
  Hook,
  Ret,
  RetType,
  ParamType,
  attach,
  detach,
  agentTarget
} from 'sidecar'

import { codeRoot } from '../commonjs/code-root'

const initAgentScript = fs.readFileSync(path.join(
  codeRoot,
  'src',
  'init-agent-script.js',
), 'utf-8')

@Sidecar(
  'WeChat.exe', 
  initAgentScript,
)
class ChatboxSidecar extends SidecarBody {
  @Call(agentTarget('callLoginQrcodeFunction'))
  callLoginQrcode (
    forceRefresh: boolean,
  ):Promise<null> { return Ret(forceRefresh) }

  @Call(agentTarget('getMyselfInfoFunction'))
  getMyselfInfo ():Promise<string> { return Ret() }

  @Hook(agentTarget('hookLogoutEventCallback'))
  logoutEvent (
    @ParamType('int32', 'U32') bySrv: number,
  ) { return Ret(bySrv) }
}

async function main () {
  const sidecar = new ChatboxSidecar()
  await attach(sidecar)

  console.log(await sidecar.getMyselfInfo())

  sidecar.on('hook', ({ method, args }) => {
    console.log('method:', method)
    console.log('args:', args)
  })

  process.on('SIGINT',  () => detach(sidecar))
  process.on('SIGTERM', () => detach(sidecar))
}

main().catch(console.error)

Some of this code was taken from wechaty-xp, just experimenting with sidecar because this is my first time. Will later use this with a newer version of WeChat. I am currently using the latest version of "sidecar": "^1.0.19".

huan commented 2 years ago

Thanks for the new information.

I will take a look when I got time with a windows VPS . (Currently I have no windows dev machine)

Have you joined the XP WeChat room? If not, please feel free to san the below qrcode to join and ask your question over there, with other sidecar users.

Screenshot_20220307-085900

KevinGong2013 commented 9 months ago

Enable experimentalDecorators and emitDecoratorMetadata in tsconfig.json

huan commented 8 months ago

Hi, anyone interested in Puppet XP will be welcome to join the Discord for future discussion. Invitation link: https://discord.gg/uE8Tb77VBm

Happy New Year 2024!