Thanks to Joroen Mostert's comment, I was able to piece together some code.
foreach (var type in types)
{
var callsShow = false;
foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var byteArray = method.GetMethodBody()?.GetILAsByteArray();
if (byteArray == null)
{
continue;
}
var bytes = BitConverter.ToString(byteArray);
var isMatch = Regex.IsMatch(bytes, "14-.*-28-.*-00-2B-26");
callsShow = callsShow || isMatch;
}
if (!callsShow)
{
MightBeBad(type);
}
}
I produced the regex by experimentation, repeatedly calling Friends.Show
in one method with various parameters and generic parameter configurations and looking for repeated sequences in the bytes. YMMV
Out of the hundreds of classes examined, 2 true positives and 10 false positives were found. The false positives were calling from inside try blocks and other unusual situations. Still, few enough to examine manually.
Also note: the pattern can differ between Debug and Release builds.