Reverse-engineered TypeScript SDK for MiChat (com.michatapp.im) — 99 API endpoints on im-gb.com.
Built from live traffic interception (HTTP Toolkit) + static analysis (JADX decompiler).
cd michat-sdk
npm install
npm run buildimport { MiChat } from './dist/index.js';
// Login with existing token (from HTTP Toolkit / Frida capture)
const mc = new MiChat({
credentials: {
uid: '7407392378484736',
token: 'MpchLTBRurqDpDGZSKRzvwVPeIynkZsjRUf+uU69vTU=',
sessionId: 'f1fa49c6602f44f9b9724680cf801cc0',
deviceId: '83051789825287428',
},
});
// Now call any endpoint
const balance = await mc.walletBalance();
const vip = await mc.vipStatus('michat_vip');
const viewers = await mc.whoLooksMeCount();If you captured a token from HTTP Toolkit or Frida:
const mc = new MiChat({
credentials: {
uid: '7407392378484736',
token: 'd8eshhOPgXup7yd7IytEXau2jHcxnTQpRV3Cc/haIa4=',
sessionId: 'f1fa49c6602f44f9b9724680cf801cc0',
deviceId: '83051789825287428',
},
});
// Token rotates every ~30s, so capture fresh ones
// From HTTP Toolkit MCP: events_list → extract token from URL paramsimport { MiChat } from './dist/index.js';
const mc = new MiChat();
// Step 1: Send SMS verification code
await mc.verifyCode({
mobile: '6281234567890', // phone with country code
cc: '62', // country code
});
// Step 2: Login with the SMS code
const loginResp = await mc.loginCode({
mobile: '6281234567890',
cc: '62',
code: '123456', // SMS code received
});
// Step 3: Extract credentials from response
if (loginResp.resultCode === 0) {
mc.setCredentials({
uid: loginResp.data.uid,
token: loginResp.data.token,
sessionId: loginResp.data.sessionId,
deviceId: 'your-device-id',
});
}// Check if user has password
const status = await mc.signupStatus({
mobile: '6281234567890',
cc: '62',
});
// Login with password
const loginResp = await mc.loginPwd({
mobile: '6281234567890',
cc: '62',
password: 'yourpassword',
});const loginResp = await mc.loginFirebase({
idToken: 'firebase-id-token',
});// Check if user exists
const exists = await mc.userExists({
mobile: '6281234567890',
cc: '62',
});
// Register
const regResp = await mc.register({
mobile: '6281234567890',
cc: '62',
nickname: 'NewUser',
password: 'newpassword',
});Server returns ALL viewer profiles despite maskFlag: true (client-side blur only).
// This works without VIP — returns count
const count = await mc.whoLooksMeCount();
// → { resultCode: 0, data: { totalCount: 33, newCount: 1 } }
// This needs VIP BUT returns full data when it works:
// uid, avatar URL, birthday, exact distance, gender, view count, timestamp
// All in plaintext despite maskFlag: true
// To dump all viewers (needs valid token):
const viewers = await mc.whoLooksMeList(0);
// → { resultCode: 0, data: { maskFlag: true, userList: [...] } }Server accepts ANY GPS coordinates without validation.
// Appear in Tokyo
await mc.updateLocation(35.6762, 139.6503);
// → { resultCode: 0 } ← ACCEPTED!
// Appear in New York
await mc.updateLocation(40.7128, -74.0060);
// → { resultCode: 0 } ← ACCEPTED!
// Appear in London
await mc.updateLocation(51.5074, -0.1278);
// → { resultCode: 0 } ← ACCEPTED!
// Get nearby users at spoofed location
const nearby = await mc.nearbyUsers(0);
// Clean up
await mc.cleanLocation();Returns user level for any UID (even fake ones).
const levels = await mc.rccInfo(['1000000000000001', '2000000000000001']);
// → { resultCode: 0, data: [{ uid: 1000000000000001, level: 20 }, ...] }mc.verifyCode(body) // Send SMS code
mc.loginCode(body) // Login with SMS code
mc.loginBound(payload, ckey) // Login with bound account (encrypted)
mc.loginPwd(body) // Login with password
mc.loginFirebase(body) // Login with Firebase
mc.loginV4(body) // Login v4
mc.authLoginV5(body) // Auth login v5
mc.register(body) // Register new user
mc.userExists(body) // Check if user exists
mc.forgotPwd(body) // Forgot password
mc.verifyActiveDays() // Verify active days
mc.mobileStatus(body) // Mobile status
mc.searchPassport(body) // Search users
mc.tokenAk(payload) // Token refresh (encrypted)
mc.logout() // Logoutmc.userInfo(body) // Get user info
mc.userUpdate(body) // Update profile
mc.userConfig() // Get config
mc.userProfile(body) // Get profile
mc.userBinding() // Get binding
mc.changePhone(body) // Change phone
mc.getProfile() // Get own profile (encrypted)
mc.rccInfo(uids) // Bulk user level lookupmc.vipStatus(scene) // VIP status (scene: 'michat_vip' | 'spotlight')
mc.vipConfig(scene, body) // VIP config
mc.vipSkuList(scene, body) // SKU list
mc.vipOpen(scene, body) // Open VIP
mc.vipBuyCheck(scene, body) // Buy check
mc.vipUsersInfo(fuids) // Bulk VIP level lookup
mc.vipSpotlight() // Spotlight status
mc.vipUserInfo(body) // VIP user info
mc.vipDiscountQuery() // Discount query
mc.gbStatus() // Golden booth status
mc.gbSet(body) // Set golden booth
mc.coinRedeemSwitch() // Coin redeem switch
mc.walletBalance() // Wallet balancemc.whoLooksMeCount() // Viewer count (unencrypted, no VIP needed)
mc.whoLooksMeList(nextIndex) // Viewer list (VIP needed, data leaked)
mc.whoLooksMePass(body) // Pass on viewer
mc.whoLikesMeCount() // Who likes me count (encrypted)mc.updateLocation(lat, lng) // Spoof GPS (no validation!)
mc.cleanLocation() // Clean location
mc.nearbyUsers(index) // Nearby users (encrypted)mc.addFriend(body) // Add friend
mc.replyFriend(body) // Reply to request
mc.applyFriend(body) // Apply request
mc.friends() // Get friends list
mc.deleteFriend(body) // Delete friend
mc.remarkFriend(body) // Remark friendmc.contactUpload(body) // Upload contacts
mc.contactSync() // Sync contacts
mc.contactPull() // Contact landing page
mc.contactPullCard(body) // Pull card
mc.contactEvictCard(body) // Evict cardmc.checkMatchRule(body) // Check match rule
mc.saveMeeyouUser(body) // Save user info
mc.updateMeeyouUser(body) // Update user info
mc.getMeeyouUser(body) // Get user info
mc.getRecommendList(body) // Get recommend list
mc.sayHi(body) // Say hi
mc.meeyouPass(body) // Pass
mc.savePicture(body) // Save picture
mc.deletePicture(body) // Delete picture
mc.userMemberInfo(body) // Member infomc.dispatch() // Get CMS chat servers
mc.sync() // Sync state (encrypted)
mc.revokeMsg(body) // Revoke messagemc.cfgSync() // Config sync (encrypted)
mc.initConfigs() // Init configs (encrypted)
mc.fdsPagesOrder() // Pages ordermc.inviteCreate() // Create invite link
mc.pushRegister(payload, ckey) // Register push
mc.userVersion() // User version
mc.userDfp() // User DFP
mc.promotionSign() // Promotion sign
mc.webScan(body) // Web QR scan
mc.webConfirm(body) // Confirm web login┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ SDK Client │────▶│ HTTP Client │────▶│ im-gb.com │
│ (index.ts) │ │ (client.ts) │ │ (nginx) │
└─────────────┘ └──────────────┘ └─────────────┘
│
┌─────┴─────┐
│ Headers │
│ - UA-ZX │
│ - Host │
│ - Token │
└───────────┘
user-agent-zx: Honor/BVL-AN16/Android/9/12081/1.4.759/en_US/3x/googleplay/Honor
content-type: application/json; charset=UTF-8
content-encrypted-zx: 1 (when encrypted)
content-ckey: <hex> (when using CKey encryption)
skip-encryption: true (some endpoints)
- AES/CBC/PKCS5Padding — IV:
0102030405060708 - RSA/ECB/PKCS1Padding — for key exchange
- Cipher types: 1=RSA, 2=CKey enc, 3=CKey dec, 4=SKey enc, 5=SKey dec
- Native implementation via OpenSSL 1.0.0a (JNI)
- Full crypto details in
src/crypto/(requires Frida to capture keys)
For educational and authorized security research only.