yowsup
yowsup copied to clipboard
Backup Token
I'm trying to register (request sms) with my number and got an error:
{"login":"xxxxxxxxxxxxx","param":"backup_token","reason":"bad_param","status":"fail"}
It was working fine until last week
I got this error too, with both sms and call request.
yowsup.common.http.warequest - Passing Config to WARequest is deprecated, pass a YowProfile instead yowsup.common.http.warequest - b'{"login":"xxxxxxxxxxxx","param":"backup_token","reason":"bad_param","status":"fail"}\n' status: b'fail' reason: b'bad_param' param: b'backup_token' login: b'xxxxxxxxxxxx'
Same a problem for me!
This is a new parameter added lately and is required.
I have same problem... Is there any solution?
Same here
yowsup-cli v3.2.1 yowsup v3.3.0 consonance v0.1.5 dissononce v0.34.3 python-axolotl v0.2.2 cryptography v2.5 protobuf v3.0.0
{"login":"xxx","param":"backup_token","reason":"bad_param","status":"fail"}
I'm working on a solution
Alright after setting up the reverse engineering environment I was able to debug the WhatsApp application and decompiled the smali source code to java for easier readability. (I'll later publish a setup guide for other contributors)
The backup_token is generated the first time the user registers and then saved in a local backup_token
file.
I've written a guide on how to generate this backup_token with JS examples, someone else need to implement them in python and create a PR for this library. I couldn't test the example scripts against WhatsApp, so if something fails please let me know.
-
Generate the base string by joining the result of the following two parts into a single string
-
Constant:
A\u0004\u001d@\u0011\u0018V\u0091\u0002\u0090\u0088\u009f\u009eT(3{;ES
(Extracted from classX.0BF
.A0L
)const constant = "A\u0004\u001d@\u0011\u0018V\u0091\u0002\u0090\u0088\u009f\u009eT(3{;ES"; let backup_token_constant = ""; for (let i = 0; i < constant.length; i++) { backup_token_constant += String.fromCharCode(constant.charCodeAt(i) ^ 18); } return backup_token_constant;
Result:
S\x16\x0FR\x03\nD\x83\x10\x82\x9A\x8D\x8CF:!i)WA
-
The last 4 digits of the users phone number
"11234567890".slice(-4);
Result:
7890
-
-
Convert the base string into a buffer
const backup_token_constant = "S\x16\x0FR\x03\nD\x83\x10\x82\x9A\x8D\x8CF:!i)WA"; const last_digits = "7890"; const base = backup_token_constant + last_digits; const buffer = Buffer.from(base);
Result:
<Buffer 53 16 0f 52 03 0a 44 c2 83 10 c2 82 c2 9a c2 8d c2 8c 46 3a 21 69 29 57 41 37 38 39 30>
or as decimal binary:[83, 22, 15, 82, 3, 10, 68, 131, 16, 130, 154, 141, 140, 70, 58, 33, 105, 41, 87, 65, 55, 56, 57, 48]
-
Generate a 16 bytes long sha1 key with 16 iterations and a 4 bytes long salt using the Password-Based Key Derivation Function 2 (PBKDF2) based on the previous
buffer
andsaltA
value.WhatsApp on Android uses the
javax.crypto.SecretKeyFactory
withPBKDF2WithHmacSHA1And8BIT
(Extracted from classX.0BA
.A06()
). In Java you have to usePBKDF2WithHmacSHA1
and a keylength of 128.The NodeJS equivalent
crypto.pbkdf2Sync()
can be used to generate the key:const crypto = require("crypto"); // buffer from step 2 const salt = crypto.randomBytes(4); // <Buffer ee 1b 75 2e> const iterations = 16; const keylength = 16; // in java is the keylen 128 const key = crypto.pbkdf2Sync(buffer, salt, iterations, keylength, "sha1");
-
Generate an aes-128-ofb cipher based on the previous sha1 key and 16 bytes long IV and random 20 bytes buffer as input
const crypto = require("crypto"); const IV = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-128-ofb', key, IV); const encrypted = cipher.update(crypto.randomBytes(20))
-
Construct the final backup_token by combining
[0, 2]
,salt
,IV
,encrypted
Buffer.concat([Buffer.from([0, 2]), salt, IV, encrypted])
Final Script
const crypto = require("crypto");
const constant = "A\u0004\u001d@\u0011\u0018V\u0091\u0002\u0090\u0088\u009f\u009eT(3{;ES";
let backup_token_constant = "";
for (let i = 0; i < constant.length; i++) {
backup_token_constant += String.fromCharCode(constant.charCodeAt(i) ^ 18);
}
const last_digits = "11234567890".slice(-4);
const base = backup_token_constant + last_digits;
const buffer = Buffer.from(base);
const salt = crypto.randomBytes(4);
const iterations = 16;
const keylength = 16; // in java is the keylen 128
const key = crypto.pbkdf2Sync(buffer, salt, iterations, keylength, "sha1");
const IV = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-128-ofb', key, IV);
const encrypted = cipher.update(crypto.randomBytes(20))
const backup_token = Buffer.concat([Buffer.from([0, 2]), salt, IV, encrypted])
console.log(backup_token.toString("hex"))
Example backup token: 0002cf3550ec083dd5b7618b54746c9c8dfaabbd8e1dd21d1fb8e942ce3ab81c4a0ff1e03e8c8fb98e5a
import secrets
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import OFB
from cryptography.hazmat.primitives.ciphers.base import Cipher
BACKUP_TOKEN_CONSTANT = b"S\x16\x0FR\x03\nD\x83\x10\x82\x9A\x8D\x8CF:!i)WA"
BACKUP_TOKEN_HEADER = b'\x00\x02'
def get_backup_token(phone: str):
tail = phone[-4:].encode("ascii")
base = BACKUP_TOKEN_CONSTANT + tail
salt = secrets.token_bytes(4)
key = PBKDF2HMAC(
algorithm=hashes.SHA1(),
length=16,
salt=salt,
iterations=16
).derive(base)
iv = secrets.token_bytes(16)
cipher = Cipher(AES(key), mode=OFB(iv))
encryptor = cipher.encryptor()
payload = secrets.token_bytes(20)
encrypted = encryptor.update(payload)
result = b"".join([BACKUP_TOKEN_HEADER, salt, iv, encrypted])
return result.hex()
Converted to python, checked on non-random salt, IV and payload (random 20 bytes)
salt = [0, 1, 2, 3]
IV = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
payload = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
The results in JS code and Python code match ('000200010203000102030405060708090a0b0c0d0e0f67fa2d28f830f0333d868a43d35da3e75118141a'
)
starting working on PR
@Flam3rboy do we know how backup token is passed? I tried base64 and hex and insert it as ,"backup_token" but it didn't work. Are there frameworks in java or js like yowsup where it was implemented?
more effort converting java to pyton, we already pissed off converting smali to java ...
@leotrubach I'm currently investigating how the backup token is passed to WhatsApp and will let you know when I find anything 👍
When the registration request is constructed the following parameters are passed to the JniBridge
The backup_token is probably named something else, because I can't find any property named backup_token
Okay, i decoded some parts of hashmap, so probably backup token isn't in that hashmap, which means it could be one of v6 or v7
offline_ab: '{"exposure":[],"metrics":{}}'
network_radio_type: seems like it is now 3 bytes - '111'
hasinrc - '1'
sim_operator_name: "T-Mobile"
pid: '3744'
sim_state: '5'
token: 'HQL+1iodePFzduaN3VrQUIh4vks=' which is bytes[20] '1d 02 fe d6 2a 1d 78 f1 73 76 e6 8d dd 5a d0 50 88 78 be 4b' or [29, 2, 254, 214, 42, 29, 120, 241, 115, 118, 230, 141, 221, 90, 208, 80, 136, 120, 190, 75]
rc: '0'
client_metrics: '{"attempts":11,"was_activated_from_stub":false}'
mistyped: '7'
simnum: '0'
read_phone_permission_granted: '0'
network_operator_name: 'Android"
The backup_token is generated the first time the user registers and then saved in a local
backup_token
file.
Where is the location in project and the format that we should save this file?
@mrhghhgh It is saved as binary in /data/data/com.whatsapp/files/backup_token
@mrhghhgh It is saved as binary in
/data/data/com.whatsapp/files/backup_token
Thanks, but is this an android directory? I was using yowsup in desktop ubuntu before this error be appeared and in yowsup project folder or ubuntu there isn't any directory like this. Please help me again
The real question is not where it saved, but how it is sent during registration?
so is there a solution or this is not usable any more ?
so is there a solution or this is not usable any more ?
I'm wondering the same
well its easy if you can follow how its generated and sent (encoded) in apk file, use jadx-gui to find out
Thank you .. if I could understand what to do I would not have asked …
Guy A
On 25 Feb 2022, at 3:00, assegaf @.***> wrote:
well its easy if you can follow how its generated and sent (encoded) in apk file, use jadx-gui to find out
— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.
register using real android phone and find all data in /data/data/com.whatsapp to be used by yowsyup
Thank you.
I don’t have android. Can it be done by computer ( windows / linux ) or by iphone ?
Guy A
On 25 Feb 2022, at 12:58, assegaf @.***> wrote:
register using real android phone and find all data in /data/data/com.whatsapp to be used by yowsyup
— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.
Can any one just add the line how to call the function? What fields should be passes.
Guy A
On 25 Feb 2022, at 12:58, assegaf @.***> wrote:
register using real android phone and find all data in /data/data/com.whatsapp to be used by yowsyup
— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.
Has anyone found a fix?
its common encoding parameter aes hash SecretKeySpec secretKeySpec = new SecretKeySpec(new SecretKeySpec(C015602t.m20338A06(obj.getBytes(), A0D, 16, 128).getEncoded(), "AES").getEncoded(), "AES/OFB/NoPadding"); etc etc ..
but the main problem its using Android BackupAgentHelper mechanism, which is upload your backup_token to google cloud. so basically if you register and able to generate the hash, its a trap isnt in cloud there is no your backup_token anywhere.
Has anyone know where on android client saves: expid, fdid, id ?
has anyone solved this ? i am trying this for first time.
i will be happy if you add it here ...
On Thu, Mar 3, 2022 at 10:33 PM varknov @.***> wrote:
i found the way and how is sent, registration working. interested ones can contact me: @.***
— Reply to this email directly, view it on GitHub https://github.com/tgalal/yowsup/issues/3123#issuecomment-1058462799, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJTXH2TYTKCVDPSSC33QOW3U6EO2ZANCNFSM5OIRWN5Q . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you commented.Message ID: @.***>
--
~Guy
Ya .. well. Good luck with btc lol ..
Guy A
On 3 Mar 2022, at 22:33, varknov @.***> wrote:
i found the way and how is sent, registration working. interested ones can contact me: @.***
— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.