The outputs I'm getting are only 2x the length of the input strings so any kind of brute force programme would be fine. Thanks.
Recovering an arbitrary function $f:M \rightarrow N$ from samples $x_i, f(x_i)$ is clearly impossible without additional information unless the given $x_i$ cover $M$ or unless $N$ is of size one, since an arbitrary continuation can be chosen on the remaining inputs. By the same token, it is trivial to find some function that reproduces the input-output behaviour of $f$ (for instance one may just pick a function that takes inputs outside the given values to some constant output in the codomain of the function).
Finding the simplest or most efficient function that reproduces some given input-output behaviour is believed to be difficult in general, even when a full description of the target function is given to the adversary and even when domain and codomain are fairly small. For instance, the paper Partitions in the S-Box of Streebog and Kuznyechik by Leo Perrin basically showed a surprisingly efficient way to implement the S-box of the Russian encryption algorithm Kuznyechik (and the Russian hash function Streebog) as well as the techniques used to obtain this representation and won the best paper award at FSE 2019. The S-box in question is a function that takes an 8-bit value to another 8-bit value and is completely public. Hence, even for functions that small, recovering an efficient function representation from the value table will not be easy in the general case.
As it was mentioned in the comments, you could try to use machine learning. The open-source software WEKA might help you to get started.
One possibility is to use the PART classifier to generate a decision list for each output bit (as a function of the input bits). Another possibility is to use the JRip classifier to generate a ruleset.
Obviously, many input bits require a large dataset and usually generate a large decision list or ruleset.