Skip to content

Instantly share code, notes, and snippets.

@dvas0004
Created October 26, 2018 14:57
Show Gist options
  • Save dvas0004/e4f2f65ae5d66491adda99d51dfc2b57 to your computer and use it in GitHub Desktop.
Save dvas0004/e4f2f65ae5d66491adda99d51dfc2b57 to your computer and use it in GitHub Desktop.
grpc-web reverse engineer
import jsbeautifier
import requests
import pprint
enumerateMessagesSearchString = 'exportSymbol("proto.'
r = requests.get('http://localhost:8081/dist/main.js')
jsInput = r.text
pretty_js = jsbeautifier.beautify(jsInput).split('\n')
messages = {}
namespaces = set()
for s in pretty_js:
if enumerateMessagesSearchString in s:
symbols = s.split("exportSymbol")
for sym in symbols:
if 'proto' in sym:
messages[sym.split('"')[1]] = {}
namespaces.add(sym.split('"')[1].split(".")[1])
print '==================== URL Endpoints ===================='
for namespace in list(namespaces):
for s in pretty_js:
if "/{}.".format(namespace) in s:
print "Discovered Endpoint: {}".format(s.split('"')[1])
for message in messages:
for idx, s in enumerate(pretty_js):
if '{}.toObject ='.format(message) in s:
searchIndex = idx + 1
endString = ""
while (endString.strip() != "};"):
search_js = pretty_js[searchIndex]
# edge case when empty message
if "{};" in search_js:
endString = "};"
break
fieldParts = search_js.strip().split(":")
if len(fieldParts) > 1:
fieldName = fieldParts[0]
fieldMeta = fieldParts[1].strip()
if 'getFieldWithDefault' in fieldMeta:
fieldDefault = fieldMeta.strip().split(")")[0].split(",")[-1]
fieldType = "Primitive with default value {}".format(fieldDefault)
elif 'getRepeatedField' in fieldMeta:
fieldType = "Repeated Field"
elif 'toObjectList' in fieldMeta:
nestedObject = fieldMeta.split(",")[1]
fieldType = "Nested Object: {}".format(nestedObject)
else:
fieldType = "Unknown"
messages[message][fieldName]=fieldType
searchIndex+=1
endString = search_js
break
pp = pprint.PrettyPrinter(indent=4)
print '==================== Messages ===================='
pp.pprint(messages)
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse);
rpc SearchResults (Empty) returns (SearchResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
string test = 2;
}
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
message Empty {
}
==================== URL Endpoints ====================
Discovered Endpoint: /helloworld.Greeter/SayHello
Discovered Endpoint: /helloworld.Greeter/SearchResults
==================== Messages ====================
{
u'proto.helloworld.Empty': { },
u'proto.helloworld.HelloRequest': { u'name': 'Primitive with default value ""'},
u'proto.helloworld.HelloResponse': { u'message': 'Primitive with default value ""',
u'test': 'Primitive with default value ""'},
u'proto.helloworld.Result': { u'snippetsList': 'Repeated Field',
u'title': 'Primitive with default value ""',
u'url': 'Primitive with default value ""'},
u'proto.helloworld.SearchResponse': { u'resultsList': 'Nested Object: proto.helloworld.Result.toObject'}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment