There’s a filter called all_plugins
that seems to do the trick for me:
add_filter( 'all_plugins', 'wpse156903_hide_plugins' );
function wpse156903_hide_plugins( (array) $plugins ) {
// let's hide akismet
if( in_array( 'akismet/akismet.php', array_keys( $plugins ) ) ) {
unset( $plugins['akismet/akismet.php'] );
}
// hide multiple plugins
$hidearr = array(
'plugin1/plugin-file.php',
'plugin2/plugin-file2.php',
// and so on
);
foreach( $hidearr as $hide_me ) {
if( in_array( $hide_me, array_keys( $plugins ) ) ) {
unset( $plugins[$hide_me] );
}
}
return $plugins;
}
Of course you’d replace akismet/akismet.php
with the path to your plugin file. (I picked on Akismet because it’s the first plugin in the list on my site.)
This function masks the existence of the plugin in question in both the Network > Plugins and Site > Plugins lists.